Distroless images contain only the application and its runtime dependencies. They do not contain package managers, shells or any other programs we would expect to find in a standard Linux distribution.
Restricting what's in your runtime container to precisely what's necessary for your app is a best practice employed by Google and other tech giants that have used containers in production for many years. It improves the signal to noise of scanners (e.g. CVE) and reduces the burden of establishing provenance to just what you need.
WhiteSource identifies CentOS and RPM-based dependencies by checking which packages reside in the /var/lib/yum/yumdb/ folder. Therefore, in order for WhiteSource to support scanning containers created from distroless images which contain CentOS or RPM-based dependencies, the dependencies must reside in an identical format within the /var/lib/yum/yumdb/ folder of the container created from the distroless image as well.
Step by Step Guide
In order for WhiteSource to support the scanning of your distroless images with CentOS-based dependencies, follow the steps detailed below and add any necessary commands to your Dockerfile. Each step contains a snippet from an example Dockerfile which may need to be modified to match your specific environment. NOTE: The <dependency_list> parameter in steps 3 and 4 should be replaced with a space-delimited list of dependencies.
Create a builder container. This is a temporary container used for installing the open-source dependencies that should be scanned.
FROM centos:7 AS builder
Create a distroless-container-preparation-directory which will be used to transfer your open-source dependencies to the ‘distroless container’ and install yum-utils.
RUN mkdir -p /packages/extracted/var/lib/yum/yumdb/
RUN yum -y install cpio yum-utils
Install and then reinstall any open-source dependencies WhiteSource should scan onto the builder container. Reinstalling the dependencies ensures the alteration of the yum-database in /var/lib/yum/yumdb in the builder container, allowing WhiteSource to understand which dependencies were installed.
RUN yum -y install <dependency_list>
RUN yum -y reinstall <dependency_list>
Copy the changed files from yumdb to the distroless-container-preparation-directory in step 2. NOTE: The changed files used in this example are determined by checking whether the modification time is under 15 minutes.
RUN find . -cmin -15 -type d | grep -v - | while read line; do mkdir -v /packages/extracted/var/lib/yum/yumdb/$line; done;
RUN find . -cmin -15 -type d | grep - | while read line; do LEADCHAR=$(echo $line | cut -d '/' -f2;); cp -rv $line /packages/extracted/var/lib/yum/yumdb/$LEADCHAR/; done;
RUN yumdownloader --destdir=/packages <dependency_list>
Continue downloading and extracting the RPMs.
RUN for RPM in ../*.rpm; do rpm2cpio $RPM | cpio -idmv; done;
RUN for RPM in *.rpm; do echo "$RPM" >> /packages/extracted/billofmaterial.txt; done;
RUN mkdir /packages/extracted/tmp/
COPY assets/busybox-x86_64 /packages/extracted/bin/busybox
RUN for i in $(./busybox --list); do ln -s busybox $i; done;
RUN ln -sv java* java
Clean up unused artifacts.
RUN rm -r usr/share/doc
RUN rm -r usr/share/man
Create the ‘distroless container’ and copy the dependencies from the builder container to a synthetic yumdb in the ‘distroless container’.
# Enable LD_DEBUG to get useful infos about linking issues
COPY --from=builder /packages/extracted/ /
COPY assets/demo.jar /app/demo.jar