Anchore Engine: Container image vulnerability scanning

Maarten Smeets

Applications nowadays, are usually deployed inside containers. A container consists of libraries and tools which allow the application to run inside. Since there can be exploitable vulnerabilities, it is not only important to take security into account for your application, but also for the container it runs in. There are various tools available to scan container images for those vulnerabilities. Having little experience with them, but recognizing the importance of having such a tool, I decided to give Anchore Engine a try. Why? Because it appeared popular when looking for tools, it has an open source variant which I can appreciate and it was very easy to get started with. In addition, it provides several integration options which make using it easy, such as a Jenkins plugin and a Kubernetes Admission Controller. In this blog post I’ll describe my first impression/experiences.

Getting started

Anchore Engine provides various ways in which you can install it here. I decided to follow the Docker Compose quickstart instruction here. I will not repeat the entire quickstart since it is straightforward, but  provide a quick example:

 #Download and run docker-compose file  
 curl https://docs.anchore.com/current/docs/engine/quickstart/docker-compose.yaml > docker-compose.yaml  
 docker-compose up -d  
    
 #Check status of feeds (first time updating can take a while)  
 docker-compose exec api anchore-cli system feeds list  
    
 #Block until complete  
 docker-compose exec api anchore-cli system wait  
    
 #Start analysis  
 docker-compose exec api anchore-cli image add openjdk:11.0.6-jre-slim  
    
 #get status  
 docker-compose exec api anchore-cli image list  
    
 #Show vulnerabilities  
 docker-compose exec api anchore-cli image vuln openjdk:11.0.6-jre-slim all  

This gives you a list of vulnerabilities of the image you indicated you wanted scanned. For example for openjdk:11.0.6-jre-slim:

If you want to scan multiple images, for example to determine the most secure JRE 11.0.6 image, you can do the following in a Bash script:

 strings=(  
 openjdk:11.0.6-jre-buster  
 openjdk:11.0.6-jre  
 openjdk:11.0.6-jre-slim-buster  
 openjdk:11.0.6-jre-slim  
 openjdk:11.0.6-jre-stretch  
 adoptopenjdk:11.0.6_10-jre-openj9-0.18.1  
 adoptopenjdk:11.0.6_10-jre-hotspot  
 adoptopenjdk:11.0.6_10-jre-openj9-0.18.1-bionic  
 adoptopenjdk:11.0.6_10-jre-hotspot-bionic  
 adoptopenjdk/openjdk11:jre-11.0.6_10-ubuntu  
 adoptopenjdk/openjdk11:jre-11.0.6_10  
 adoptopenjdk/openjdk11:jre-11.0.6_10-ubi-minimal  
 adoptopenjdk/openjdk11:jre-11.0.6_10-ubi  
 adoptopenjdk/openjdk11:jre-11.0.6_10-debianslim  
 adoptopenjdk/openjdk11:jre-11.0.6_10-debian  
 adoptopenjdk/openjdk11:jre-11.0.6_10-centos  
 adoptopenjdk/openjdk11:jre-11.0.6_10-alpine  
 mcr.microsoft.com/java/jre:11u6-zulu-alpine  
 mcr.microsoft.com/java/jre:11u6-zulu-centos  
 mcr.microsoft.com/java/jre:11u6-zulu-debian8  
 mcr.microsoft.com/java/jre:11u6-zulu-debian9  
 mcr.microsoft.com/java/jre:11u6-zulu-debian10  
 mcr.microsoft.com/java/jre:11u6-zulu-ubuntu  
 azul/zulu-openjdk-alpine:11.0.6-jre  
 )  
   
 for i in "${strings[@]}"; do  
 docker-compose exec api anchore-cli image add "$i"  
 done  

Processing results

Now you have to wait a while for all the images to be scanned. If it’s done, you can process the data.

 strings=(  
 openjdk:11.0.6-jre-buster  
 openjdk:11.0.6-jre  
 openjdk:11.0.6-jre-slim-buster  
 openjdk:11.0.6-jre-slim  
 openjdk:11.0.6-jre-stretch  
 adoptopenjdk:11.0.6_10-jre-openj9-0.18.1  
 adoptopenjdk:11.0.6_10-jre-hotspot  
 adoptopenjdk:11.0.6_10-jre-openj9-0.18.1-bionic  
 adoptopenjdk:11.0.6_10-jre-hotspot-bionic  
 adoptopenjdk/openjdk11:jre-11.0.6_10-ubuntu  
 adoptopenjdk/openjdk11:jre-11.0.6_10  
 adoptopenjdk/openjdk11:jre-11.0.6_10-ubi-minimal  
 adoptopenjdk/openjdk11:jre-11.0.6_10-ubi  
 adoptopenjdk/openjdk11:jre-11.0.6_10-debianslim  
 adoptopenjdk/openjdk11:jre-11.0.6_10-debian  
 adoptopenjdk/openjdk11:jre-11.0.6_10-centos  
 adoptopenjdk/openjdk11:jre-11.0.6_10-alpine  
 mcr.microsoft.com/java/jre:11u6-zulu-alpine  
 mcr.microsoft.com/java/jre:11u6-zulu-centos  
 mcr.microsoft.com/java/jre:11u6-zulu-debian8  
 mcr.microsoft.com/java/jre:11u6-zulu-debian9  
 mcr.microsoft.com/java/jre:11u6-zulu-debian10  
 mcr.microsoft.com/java/jre:11u6-zulu-ubuntu  
 azul/zulu-openjdk-alpine:11.0.6-jre  
 )  
   
 echo Unknown,Critical,High,Medium,Low,Negligible,Image  
 for i in "${strings[@]}"; do  
 docker-compose exec api anchore-cli image vuln "$i" all | awk 'NR>1{print $3}' | sort -n | uniq -c >parse.txt  
 UNKNOWN=`cat parse.txt | grep Unknown | awk '{print $1}'`  
 CRITICAL=`cat parse.txt | grep Critical | awk '{print $1}'`  
 LOW=`cat parse.txt | grep Low | awk '{print $1}'`  
 MEDIUM=`cat parse.txt | grep Medium | awk '{print $1}'`  
 HIGH=`cat parse.txt | grep High | awk '{print $1}'`  
 NEG=`cat parse.txt | grep Negligible | awk '{print $1}'`  
 if [ -z "$UNKNOWN" ]; then  
      UNKNOWN=0  
 fi  
 if [ -z "$CRITICAL" ]; then  
     CRITICAL=0  
 fi  
 if [ -z "$LOW" ]; then  
      LOW=0  
 fi  
 if [ -z "$MEDIUM" ]; then  
      MEDIUM=0  
 fi  
 if [ -z "$HIGH" ]; then  
      HIGH=0  
 fi  
 if [ -z "$NEG" ]; then  
      NEG=0  
 fi  
 echo $UNKNOWN,$CRITICAL,$HIGH,$MEDIUM,$LOW,$NEG,"$i"  
 done  

This provides a nice comma separated list which you can use in your favorite spreadsheet for some visualization

Next, you can draw some conclusions like

  • Newer OS versions are more secure
  • Alpine does better than Debian/Ubuntu. Debian/Ubuntu does better than RHEL/CentOS
  • Slim versions do slightly better than not so slim versions
  • No OpenJDK JRE 11.0.6 images scanned have critical vulnerabilities. Very few have high severity issues
  • In the OpenJDK images, when a new version is released, the underlying libraries and tools are usually also updated, reducing the number of vulnerabilities in newer versions.

Finally

I was surprised (even though I was trying out a quickstart) in how little time I could perform a vulnerability scan of a list of images. The integration options Anchore Engine provides, also seem powerful, although I did not try them out yet. There seems little reason not to cooperate a scan like this in your CI/CD environment. I suggest you give it a try!

This is just an example of a security related challenge. The container platform itself runs on an OS which you should check. Kubernetes and its native components can have vulnerabilities. Of course you should also keep an eye on already deployed images, since new vulnerabilities can be found. I did not scan an image containing an actual application. This might have provided some additional insights. You should perform scans on your source code dependencies (see for example the OWASP dependency check here) and on the code itself (see here). Also outside of your source code it is advisable to do some security related integration tests, such as checking your HTTPS connection (e.g. cipher suites), certificates, HTTP headers, try out some XML based attacks maybe, etc. Many challenges, but for scanning container images Anchore Engine seems nice!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Next Post

Production-like Kubernetes on your laptop. Kubespray on KVM

Facebook 0 Twitter Linkedin There are various options to install a production-like Kubernetes distribution on your laptop. Previously I tried out using the Canonical stack (Juju, MAAS, Charmed Kubernetes) for this. This worked nicely but it gave me the feeling that it was a bit Canonical specific and it felt a bit […]