helm charts security

Using UBI images to minimize container vulnerabilities

Rags Srinivas
March 27, 2020 | in Container Security
| By Rags Srinivas

At Snyk, we work hard to continue improving container and cloud-native security solutions. As part of this effort, Snyk Container empowers developers to fully own the security of their container images.

One common source of vulnerabilities in containers is the base image that is pulled in as the foundation for creating your own custom images. Rather than just being reactive to new vulnerabilities, it is advisable to take a proactive approach by starting with a set of base images that are well-curated and continually updated.

In this post, we look at Red Hat Universal Base Images which helps with the objective outlined above.

What is Universal Base Image (UBI)?

Announced at the Red Hat Summit in 2019, Red Hat Universal Base Images are built on an enterprise grade platform, Red Hat Enterprise Linux (RHEL). The images are OCI-compliant container base operating system images with a variety of runtime languages and packages that are freely redistributable. These images for UBI 8 for instance are updated every time RHEL 8 base images are updated and when critical CVEs are patched

From a technical perspective, they are nearly identical to Red Hat Enterprise Linux images, which means they have great security, performance, and life cycles. They are released under a different End User License Agreement — It’s possible to build a containerized application using UBI, push it to any registry server, easily share it with others – and because it’s freely redistributable — even deploy it on non-Red Hat platforms.

A complete catalog of the UBI images is mentioned in table 4.1 of Red Hat’s Building, Running, And Managing Containers docs. These are also listed in Red Hat’s container catalog. The UBI images cover a wide array of popular development languages, including dotnet, golang, nodejs, Python, PHP and Ruby.

Complete details are available in Red Hat’s docs and FAQ but it’s fairly easy to incorporate UBI images while maintaining your workflow as we show below.

Building container images using UBI

Let’s start with a Dockerfile example for Python. it’s possible to use UBI images for different language runtimes based on a similar approach.

Here’s an auto-generated Dockerfile for a simple Python “Hello World!” example that uses flask.

FROM python
ENV PORT 8080
EXPOSE 8080
WORKDIR /usr/src/app

COPY requirements.txt . 
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

ENTRYPOINT ["python"] 
CMD ["app.py"]

Instead of using python as the base image, let’s use the UBI image from the Red Hat registry by modifying the Dockerfile as below (you may need the right credentials to be able to authenticate and use the images). Notice the only change is in the first line where we use the UBI image.

FROM registry.redhat.io/ubi8/python-36
ENV PORT 8080
EXPOSE 8080
WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

ENTRYPOINT ["python"] 
CMD ["app.py"]

Generating a containerized app with UBI as the base image is identical to generating with a non UBI image as below:

docker build -t ragsns/example-python-ubi .

Running snyk on the containerized app with UBI as the base image generates a list of vulnerabilities as shown below.

snyk test --container ragsns/example-python-ubi --file=Dockerfile          

Testing ragsns/example-python-ubi...

✗ Low severity vulnerability found in npm
  Description: RHEA-2020:0330
  Info: https://snyk.io/vuln/SNYK-RHEL8-NPM-555355
  Introduced through: npm@1:6.9.0-1.10.16.3.2.module+el8.0.0+4214+49953fda
  From: npm@1:6.9.0-1.10.16.3.2.module+el8.0.0+4214+49953fda
  Introduced by your base image (registry.redhat.io/ubi8/python-36)
  Fixed in: 1:6.13.4-1.12.14.1.1.module+el8.1.0+5466+30f75629

✗ Low severity vulnerability found in nodejs
  Description: RHEA-2020:0330
  Info: https://snyk.io/vuln/SNYK-RHEL8-NODEJS-555347
  Introduced through: nodejs@1:10.16.3-2.module+el8.0.0+4214+49953fda
  From: nodejs@1:10.16.3-2.module+el8.0.0+4214+49953fda
  Introduced by your base image (registry.redhat.io/ubi8/python-36)
  Fixed in: 1:12.14.1-1.module+el8.1.0+5466+30f75629

✗ High severity vulnerability found in systemd-pam
  Description: RHSA-2020:0575
  Info: https://snyk.io/vuln/SNYK-RHEL8-SYSTEMDPAM-552042
  Introduced through: systemd-pam@239-18.el8_1.2
  From: systemd-pam@239-18.el8_1.2
  Introduced by your base image (registry.redhat.io/ubi8/python-36)
  Fixed in: 0:239-18.el8_1.4

✗ High severity vulnerability found in systemd-libs
  Description: RHSA-2020:0575
  Info: https://snyk.io/vuln/SNYK-RHEL8-SYSTEMDLIBS-552044
  Introduced through: systemd-libs@239-18.el8_1.2
  From: systemd-libs@239-18.el8_1.2
  Introduced by your base image (registry.redhat.io/ubi8/python-36)
  Fixed in: 0:239-18.el8_1.4

✗ High severity vulnerability found in systemd
  Description: RHSA-2020:0575
  Info: https://snyk.io/vuln/SNYK-RHEL8-SYSTEMD-552048
  Introduced through: systemd@239-18.el8_1.2
  From: systemd@239-18.el8_1.2
  Introduced by your base image (registry.redhat.io/ubi8/python-36)
  Fixed in: 0:239-18.el8_1.4

✗ High severity vulnerability found in npm
  Description: RHSA-2020:0579
  Info: https://snyk.io/vuln/SNYK-RHEL8-NPM-555375
  Introduced through: npm@1:6.9.0-1.10.16.3.2.module+el8.0.0+4214+49953fda
  From: npm@1:6.9.0-1.10.16.3.2.module+el8.0.0+4214+49953fda
  Introduced by your base image (registry.redhat.io/ubi8/python-36)
  Fixed in: 1:6.13.4-1.10.19.0.1.module+el8.1.0+5726+6ed65f8c

✗ High severity vulnerability found in npm
  Description: RHSA-2020:0598
  Info: https://snyk.io/vuln/SNYK-RHEL8-NPM-557042
  Introduced through: npm@1:6.9.0-1.10.16.3.2.module+el8.0.0+4214+49953fda
  From: npm@1:6.9.0-1.10.16.3.2.module+el8.0.0+4214+49953fda
  Introduced by your base image (registry.redhat.io/ubi8/python-36)
  Fixed in: 1:6.13.4-1.12.16.1.1.module+el8.1.0+5811+44509afe

✗ High severity vulnerability found in nodejs
  Description: RHSA-2020:0579
  Info: https://snyk.io/vuln/SNYK-RHEL8-NODEJS-555367
  Introduced through: nodejs@1:10.16.3-2.module+el8.0.0+4214+49953fda
  From: nodejs@1:10.16.3-2.module+el8.0.0+4214+49953fda
  Introduced by your base image (registry.redhat.io/ubi8/python-36)
  Fixed in: 1:10.19.0-1.module+el8.1.0+5726+6ed65f8c

✗ High severity vulnerability found in nodejs
  Description: RHSA-2020:0598
  Info: https://snyk.io/vuln/SNYK-RHEL8-NODEJS-557034
  Introduced through: nodejs@1:10.16.3-2.module+el8.0.0+4214+49953fda
  From: nodejs@1:10.16.3-2.module+el8.0.0+4214+49953fda
  Introduced by your base image (registry.redhat.io/ubi8/python-36)
  Fixed in: 1:12.16.1-1.module+el8.1.0+5811+44509afe

Organization:      rags
Package manager:   rpm
Target file:       Dockerfile
Project name:      docker-image|ragsns/example-python-ubi
Docker image:      ragsns/example-python-ubi
Base image:        registry.redhat.io/ubi8/python-36
Licenses:          enabled

Tested 417 dependencies for known issues, found 9 issues.

Running the UBI-based container image is also identical to running the application based on the non-UBI image as shown below.

docker run -it -p8080:8080 ragsns/example-python-ubi

This is possible based on what is outlined in the documentation “The new Red Hat Universal Base Images enable you to build your container ONCE and freely redistribute it to multiple deployment platforms.”

Or, if you prefer to use Red Hat’s container toolset for testing or running the application, you can use the following command

podman run -p 8080:8080 ragsns/example-python-ubi

Now that we’ve seen a Python language example, rather than walk through each of the language runtime examples individually (and there may be some more minor changes required for working with the respective language runtime), let’s take a collective look at all of them.

UBI images for multiple languages

As indicated earlier, there are UBI images for multiple language runtimes. Running Snyk on the different UBI images produces an output that is summarized in the following table.

UBI ImageDependenciesVulnerabilities
registry.redhat.io/ubi8/nodejs-103739
registry.redhat.io/ubi8/python-364179
registry.redhat.io/ubi8/ruby-264819
registry.redhat.io/ubi8/php-734039
registry.redhat.io/ubi8/go-toolset37113
registry.redhat.io/ubi8/dotnet-2124810

The UBI images for the variety of languages and the low vulnerability count is as a result of Red Hat carefully curating and updating them, including the base operating system, the yum repositories used to install packages and tools, and the languages and frameworks.  This Red Hat article goes into detail, primarily by maintaining a bug list of the UBI images and how they are periodically refreshed and maintained in a process similar to what is used for the base operating system itself.

Summary and next steps

We’ve shown how easy it is to base containerized applications on UBI images for multiple language runtimes. The changes including pulling the Red Hat UBI image is fairly easy to apply and incorporate into your CI/CD or development pipeline and continue to maintain normal workflows.

From a security perspective,  UBI images are a good option for containerizing your applications since we’ve seen how the UBI images follow a rigorous maintenance process, in-line with the well-established process for the RHEL operating system . Since UBI images are available for a variety of language runtimes, using them as a base image for your containerized images will help minimize vulnerabilities in your application.

Snyk supports the security of your application development for the entire software development lifecycle, including integrations with your image registry, Dockerfile repository, CI/CD pipelines, and Kubernetes clusters, including OpenShift 4 environments. Snyk Container supports UBI and RHEL images as well as other popular Linux distros. 

You can use Snyk Container for free by signing up at https://snyk.io/signup.