By far one the most common challenge Anchore helps its users solve is the identification of vulnerabilities within their Docker container images. Anchore analysis tools will inspect container images and generate a detailed manifest of the image, a virtual 'bill of materials' that includes official operating system packages, unofficial packages, configuration files, and language modules and artifacts. Following this, Anchore will evaluate policies against the analysis result, which includes vulnerability matches on the artifacts discovered in the image.
Quite often, Docker images contain both application and operating system packages. However, in this particular post, I will focus on the identification of a specific vulnerable application package inside an image, walkthrough how it can be visualized within the Anchore Enterprise UI, and what might an approach be to remediate.
As part of Anchore Enterprise, the vulnerability data source you will be seeing comes from Snyk. I recently wrote a post discussing the choice at Anchore to add this high-quality vulnerability data source to our enterprise platform which you can read about here.
Sample Project Repo
I will be referencing this example GitHub repository located here. The idea is simple, create a war file with Maven containing a vulnerable dependency, create a Docker image containing the war file, scan it with Anchore, and see what vulnerabilities are present. It is not the intent to run this Java project or anything outside of the scope discussed above.
Viewing the Dependencies
When viewing the pom.xml
file for this project I can clearly see which dependencies I will be including.
Dependencies section of pom.xml
:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
The vulnerable artifact I've added to this particular project can be found on Maven Central here and GitHub here. I will be expecting jackson-databind 2.9.7 to contain vulnerabilities.
Building Project
Viewing the dependency tree
Since we are leveraging Maven to build this project, I can also use a Maven command to view the dependencies. The command mvn dependency:tree
will display the dependency tree for this project as seen below.
mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------< Anchore:anchore-demo >------------------------
[INFO] Building Anchore Demo 1.0
[INFO] -----------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ anchore-demo ---
[INFO] Anchore:anchore-demo:war:1.0
[INFO] +- junit:junit:jar:4.11:compile
[INFO] | - org.hamcrest:hamcrest-core:jar:1.3:compile
[INFO] - com.fasterxml.jackson.core:jackson-databind:jar:2.9.7:compile
[INFO] +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
[INFO] - com.fasterxml.jackson.core:jackson-core:jar:2.9.7:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.117 s
[INFO] Finished at: 2019-01-22T19:39:56-05:00
[INFO] ------------------------------------------------------------------------
Building a war file
To create the war file as defined in the pom.xml
I will run the command mvn clean package
. The important piece here is that package
will generate the war file and place it in the target directory as seen below.
target jvalance$ ls -la | grep anchore-demo-1.0.war
-rw-r--r-- 1 jvalance staff 1862404 Jan 22 19:50 anchore-demo-1.0.war
Building and Scanning Docker Images
For the purposes of this post, I just need to include the war file created in the previous step in our Docker image. A simple way to do this can be defined below in a Dockerfile.
FROM openjdk:8-jre-alpine
# Copy target directory
COPY target/ app/
Once I've built the image and pushed it to a container registry, I can now scan it with Anchore via the CLI command below.
anchore-cli image add docker.io/jvalance/maven-demo:latest
Viewing Vulnerabilities
Once Anchore has completed an analysis of the image successfully, I can check for non-os vulnerabilities via the following CLI command:
anchore-cli image vuln docker.io/jvalance/maven-demo:latest non-os
## The above produces the following output:
Vulnerability ID Package Severity Fix Vulnerability URL
SNYK-JAVA-COMFASTERXMLJACKSONCORE-72448 jackson-databind-2.9.7 High ! <2.6.7.2 https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-72448
SNYK-JAVA-COMFASTERXMLJACKSONCORE-72448 jackson-databind-2.9.7 High ! <2.6.7.2 https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-72448
SNYK-JAVA-COMFASTERXMLJACKSONCORE-72449 jackson-databind-2.9.7 High ! <2.6.7.2 https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-72449
SNYK-JAVA-COMFASTERXMLJACKSONCORE-72449 jackson-databind-2.9.7 High ! <2.6.7.2 https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-72449
SNYK-JAVA-COMFASTERXMLJACKSONCORE-72451 jackson-databind-2.9.7 High ! <2.6.7.2 https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-72451
SNYK-JAVA-COMFASTERXMLJACKSONCORE-72451 jackson-databind-2.9.7 High ! <2.6.7.2 https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-72451
SNYK-JAVA-COMFASTERXMLJACKSONCORE-72882 jackson-databind-2.9.7 High ! >=2.0.0 <2.9.8 https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-72882
SNYK-JAVA-COMFASTERXMLJACKSONCORE-72882 jackson-databind-2.9.7 High ! >=2.0.0 <2.9.8 https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-72882
SNYK-JAVA-COMFASTERXMLJACKSONCORE-72883 jackson-databind-2.9.7 High ! >=2.0.0 <2.9.8 https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-72883
SNYK-JAVA-COMFASTERXMLJACKSONCORE-72883 jackson-databind-2.9.7 High ! >=2.0.0 <2.9.8 https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-72883
SNYK-JAVA-COMFASTERXMLJACKSONCORE-72884 jackson-databind-2.9.7 High ! >=2.0.0 <2.9.8 https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-72884
SNYK-JAVA-COMFASTERXMLJACKSONCORE-72884 jackson-databind-2.9.7 High ! >=2.0.0 <2.9.8 https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-72884
I also have the option to login and view the vulnerabilities via the UI.
By clicking on any of the links on the far right, I can immediately be taken to Snyk's Vulnerability DB to view more information. Example: SNYK-JAVA-COMFASTERXMLJACKSONCORE-72448.
For this particular vulnerability, Snyk offers remediation advice located at the bottom. Which states: "Upgrade com.fasterxml.jackson.core:jackson-databind to version 2.6.7.2, 2.7.9.5, 2.8.11.3, 2.9.8 or higher."
Given that there are twelve known vulnerabilities found within this image, it is a best practice for a security team to go through each and make a decision with the developer on how to best triage. For the simplicity of this post, if I were to follow the suggested remediation guidance above, and upgrade my vulnerable dependency to 2.9.8, rebuild the war file, rebuild the Docker image, and scan it with Anchore, this particular vulnerability should no longer persist.
Quick Test
mvn dependency:tree
output:
Anchore:anchore-demo:war:1.0
[INFO] +- junit:junit:jar:4.11:compile
[INFO] | - org.hamcrest:hamcrest-core:jar:1.3:compile
[INFO] - com.fasterxml.jackson.core:jackson-databind:jar:2.9.8:compile
[INFO] +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
[INFO] - com.fasterxml.jackson.core:jackson-core:jar:2.9.8:compile
Once I've repeated the steps shown above to build war file, Docker image, and scan newly built image with Anchore, I can then see if the discussed vulnerability is present.
Overview of vulnerabilities
None present.
I can also view the changelog for this image to get a better sense of the modification I just made.
Below I can specifically see the version change I made to the jackson-databind library.
Conclusion
This was an intentionally simple example of how a vulnerable non-os package within a Docker image can be identified and fixed with Anchore. However, you can see how easily a vulnerable package can potentially wreak havoc if the appropriate checks are not in place. In practice, Docker image scanning should be a mandatory step in a CI pipeline, and development and security teams should maintain open lines of communication when vulnerabilities are discovered within images, and then move swiftly to apply the appropriate fixes.