When using Docker containers in production, we need to ensure that we are following best practices. In this post, we will focus on Ensure images are scanned and rebuilt to include security patches from the CIS Docker Community Benchmark which we discussed previously. The item states that you should scan your images “frequently” for any vulnerabilities and then take the necessary actions to mitigate these vulnerabilities. We will use Anchore Engine in order to accomplish this.
1. What Is Anchore Engine?
Anchore Engine is an open source tool that scans your Docker images for security vulnerabilities. Definitely a powerful tool when you are running Docker containers in production. With Anchore Engine you have an automatic check on your Docker images whether they are up to date before you run them into production. In this post we will focus on Anchore Engine, which is the open source project. Anchore also exists as an Enterprise version which provides you an easier way of configuring Anchore by means of a UI, role based access control, generate reports, etc. A comparison of features between Anchore Engine and Anchore Enterprise can be found here (near the end of the page).
Anchore Engine can be accessed by means of a RESTful API or by means of the Anchore CLI. We will use the latter in this post.
2. Install Anchore Engine
The Anchore Engine can easily be installed by following the installation instructions. A Docker image is available with Anchore Engine and besides that, a PostgreSQL database is needed. It becomes even easier because a Docker Compose yaml
file is provided. For more information on Docker Compose, we suggest reading a previous post about this topic.
So, let’s get started. First, we create a configuration directory into our home directory of, in our case, user developer
(this is different from the installation instructions where the root
path is used).
$ mkdir -p /home/developer/anchorevolume/config
Go to the just created directory /home/developer/anchorevolume/config
and download the config.yaml
file:
$ curl -O https://raw.githubusercontent.com/anchore/anchore-engine/master/scripts/docker-compose/config.yaml
We will not change anything to the default configuration but you should take a closer look at it in order to tweak it to your preferences. In our case, the default admin user admin
with password foobar
will be used.
We also need a directory to store the data for our PostgreSQL database:
$ mkdir -p /home/developer/anchorevolume/db
As mentioned before, we will run Anchore Engine by means of Docker Compose. Go to the directory /home/developer/anchorevolume
and download the docker-compose.yaml
file:
$ curl -O https://raw.githubusercontent.com/anchore/anchore-engine/master/scripts/docker-compose/docker-compose.yaml
From within the same directory, run the following command which will pull the Docker images for Anchore Engine and PostgreSQL:
$ docker-compose pull
The only thing left to do, is to run Anchore Engine in silent mode:
$ docker-compose up -d
3. Install Anchore CLI
We will use Anchore CLI in order to control the Anchore Engine. Installation of Anchore CLI is also fairly simple. We are using Ubuntu 18.04, installation instructions for other platforms are available here.
$ apt-get update $ apt-get install python-pip $ pip install anchorecli
We also had to source our .profile
file in order to get Anchore CLI working:
$ source ~/.profile
Correct installation can be verified by issuing the following command:
$ anchore-cli --version
With every other command, you will have to provide the Anchore Engine credentials by means of the parameters --u
for the user, --p
for the password and --url
for accessing the Anchore Engine API. Another way is to define these parameters as environment variables. This way, you will not have to provide them with every command. In our case, this will be:
$ ANCHORE_CLI_URL=http://localhost:8228/v1 $ ANCHORE_CLI_USER=admin $ ANCHORE_CLI_PASS=foobar $ export ANCHORE_CLI_URL $ export ANCHORE_CLI_USER $ export ANCHORE_CLI_PASS
4. Analyze a Docker Image
Now that the installation of Anchore Engine and Anchore CLI is all set and done, we are ready to analyze a Docker image. We will make use of the openjdk:10-jdk
Docker image because we are quite certain that it will contain vulnerabilities. This Docker image will not be updated anymore because it was not a Java LTS release and is being replaced by the openjdk:11-jdk
Docker image.
The only thing we need to do, is to add the Docker image to Anchore Engine, which will immediately start the analysis.
$ anchore-cli image add openjdk:10-jdk Image Digest: sha256:923d074ef1f4f0dceef68d9bad8be19c918d9ca8180a26b037e00576f24c2cb4 Parent Digest: sha256:9f17c917630d5e95667840029487b6561b752f1be6a3c4a90c4716907c1aad65 Analysis Status: not_analyzed Image Type: docker Image ID: b11e88dd885d8b2621d448f3d2099068d181c5c778c2ab0cf0f61b573fa429b7 Dockerfile Mode: None Distro: None Distro Version: None Size: None Architecture: None Layer Count: None Full Tag: docker.io/openjdk:10-jdk
We are able to monitor the progress with the list
command, which shows us the Docker images added to Anchore Engine and their respective status.
$ anchore-cli image list Full Tag Image ID Analysis Status docker.io/openjdk:10-jdk b11e88dd885d8b2621d448f3d2099068d181c5c778c2ab0cf0f61b573fa429b7 analyzing
After a few minutes, the Analysis Status turns into Analyzed. We are now able to retrieve the results. It is possible that you will need to wait a little bit longer than a few minutes. The first time Anchore Engine is run, it needs to download the vulnerabilities. This can take some time dependent of your internet bandwidth. You can check the status of the sync with the following command:
$ anchore-cli system feeds list Feed Group LastSync RecordCount vulnerabilities alpine:3.3 2019-05-19T11:45:22.273938 457 vulnerabilities alpine:3.4 2019-05-19T11:45:28.743787 681 vulnerabilities alpine:3.5 2019-05-19T11:45:36.883590 875 vulnerabilities alpine:3.6 2019-05-19T11:45:47.375153 1051 vulnerabilities alpine:3.7 2019-05-19T11:45:58.165606 1125 vulnerabilities alpine:3.8 2019-05-19T11:46:09.939298 1220 vulnerabilities alpine:3.9 2019-05-19T11:46:22.068746 1218 vulnerabilities amzn:2 2019-05-19T11:46:29.720936 167 vulnerabilities centos:5 2019-05-19T11:46:57.667760 1323 vulnerabilities centos:6 2019-05-19T11:47:37.387118 1331 vulnerabilities centos:7 2019-05-19T11:48:04.611414 788 vulnerabilities debian:10 2019-05-19T11:51:09.159110 20196 vulnerabilities debian:7 2019-05-19T11:54:29.383399 20455 vulnerabilities debian:8 2019-05-19T11:57:48.854096 21641 vulnerabilities debian:9 2019-05-19T12:00:47.974081 20412 vulnerabilities debian:unstable 2019-05-19T12:03:57.095763 21058 vulnerabilities ol:5 2019-05-19T12:04:30.601427 1232 vulnerabilities ol:6 2019-05-19T12:05:08.700762 1410 vulnerabilities ol:7 2019-05-19T12:05:39.294882 906 vulnerabilities ubuntu:12.04 None 0 vulnerabilities ubuntu:12.10 None 0 vulnerabilities ubuntu:13.04 None 0 vulnerabilities ubuntu:14.04 None 0 vulnerabilities ubuntu:14.10 None 0 vulnerabilities ubuntu:15.04 None 0 vulnerabilities ubuntu:15.10 None 0 vulnerabilities ubuntu:16.04 None 0 vulnerabilities ubuntu:16.10 None 0 vulnerabilities ubuntu:17.04 None 0 vulnerabilities ubuntu:17.10 None 0 vulnerabilities ubuntu:18.04 None 0 vulnerabilities ubuntu:18.10 None 0 vulnerabilities ubuntu:19.04 None 0
When the RecordCount of each item is different from 0, it is possible to retrieve the results:
$ anchore-cli image vuln openjdk:10-jdk os Vulnerability ID Package Severity Fix Vulnerability URL CVE-2018-1000654 libtasn1-6-4.13-3 High None https://security-tracker.debian.org/tracker/CVE-2018-1000654 CVE-2018-1000802 libpython2.7-minimal-2.7.15-4 High 2.7.15-5 https://security-tracker.debian.org/tracker/CVE-2018-1000802 CVE-2018-1000802 libpython2.7-stdlib-2.7.15-4 High 2.7.15-5 https://security-tracker.debian.org/tracker/CVE-2018-1000802 ...
The list is much longer, but this gives you an impression of what to expect: the CVE identifier, the package it applies to, the severity, whether a fix is available or not and a URL to the vulnerability itself.
When you analyze a Docker image you created yourself and execute the commands as above, you won’t see any results. We used a mykubernetesplanet:0.0.2-SNAPSHOT
Docker image we created for a previous post, which contains a Spring Boot MVC application and which is based on the openjdk:10-jdk
Docker image. We would expect the same results as above, but it shows us no vulnerabilities. When analyzing our mykubernetesplanet
Docker image, we also need to provide the Dockerfile
of the Docker image. In order to analyze the mykubernetesplanet:0.0.2-SNAPSHOT
Docker image from DockerHub, we clone the Git repository master branch to our home directory and execute the following command:
$ anchore-cli image add mydeveloperplanet/mykubernetesplanet:0.0.2-SNAPSHOT --dockerfile=/home/developer/mykubernetesplanet/Dockerfile Image Digest: sha256:0d4ec08036b2e2d3fa38130a1d2572d429630868761a9030d0325699fc8a6ddd Parent Digest: sha256:0d4ec08036b2e2d3fa38130a1d2572d429630868761a9030d0325699fc8a6ddd Analysis Status: analyzed Image Type: docker Image ID: 87b6859f00d3ac1f7f12da4732a6bb214f654a8410af8a9c102c3c5bc2cd5b1c Dockerfile Mode: Actual Distro: debian Distro Version: unstable Size: 405416787 Architecture: amd64 Layer Count: 9 Full Tag: docker.io/mydeveloperplanet/mykubernetesplanet:0.0.2-SNAPSHOT
When we retrieve the results with the vuln
command, we receive the same list as for the openjdk:10-jdk
Docker image.
5. Conclusion
We investigated Anchore Engine as a tool in order to help us identify vulnerabilities in our Docker image. With Anchore Engine, we definitely have a tool which will help us to comply to the item Ensure images are scanned and rebuilt to include security patches from the CIS Docker Community Benchmark.
Hi @mydeveloperplanet. Thanks for really helpful tutorial of using this tool. However, i wonder if this is applicable for scanning the local Docker Image (which is built from `docker build ..` ), or the Docker Image which i stored at `hub.docker.com`. The error message response from running the this command
`anchore-cli add /:`
“`Error: cannot fetch image digest/manifest from registry
HTTP Code: 400“`
Could you please help in this case ? Thanks a lot.
LikeLike
In the above post, I used DockerHub as Docker repository. If you want to analyze local Docker images you built yourself and are present in your local Docker repository, you have to indicate that you want to use that repository and you will have to provide the Dockerfile to the command (I guess that replacing myrepo.example.com with localhost should work):
anchore-cli image add myrepo.example.com:5000/app/webapp:latest –dockerfile=/path/to/Dockerfile
More info can be found at https://anchore.freshdesk.com/support/solutions/articles/36000003482-adding-images
Hope this helps.
LikeLike
Hi , thanks for your quick response. Actually i tried `docker login…` first to see which registry will be logged within my account and it was `https://registry-1.docker.io` , then i must add the registry to the registry list following `anchore-cli registry add registry-url USERNAME PASSWORD` . It tried to log it with given username password i provided (for Docker Hub) successfully. Then follow your instruction i’m able to get the my Docker image (on the private repo) analyzed. I will try to get the local Docker image analyzed too. Thanks so much for your help
LikeLike