Using UBI images to minimize container vulnerabilities
Rags Srinivas
2020年3月27日
0 分で読めます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.
Complete details are available in Red Hat's documentation on Building, Running, And Managing Containers. Certified container images 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.
You can find additional information on UBI images in Red Hat's 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 Image | Dependencies | Vulnerabilities |
---|---|---|
registry.redhat.io/ubi8/nodejs-10 | 373 | 9 |
registry.redhat.io/ubi8/python-36 | 417 | 9 |
registry.redhat.io/ubi8/ruby-26 | 481 | 9 |
registry.redhat.io/ubi8/php-73 | 403 | 9 |
registry.redhat.io/ubi8/go-toolset | 371 | 13 |
registry.redhat.io/ubi8/dotnet-21 | 248 | 10 |
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.