PAVEL KANN
Building a test environment for Docker security scanning
Building a test environment for Docker security scanning

If you would like to experiment with integrationg of Docker security tools into CI/CD process I would like to provide the below guide.

The main idea is to demonstrate how you could implement automated checks for various Docker security aspects (described in previous articles) and check for security issue in Dockerfiles and Docker images that you are using and building during the development and product shipment.

I have chosen the following suite of tools to cover most of Docker security landscape:
    1. Dockerfile instructions linter tool - Hadolint tool;
    2. Checking for the correctness and secureness of the final and intermediate images - Dockle tool;
    3. Checking for known vulnerabilities (CVEs) in a base image and several dependencies files - Trivy tool;
    Below you can find three different approaches to perform a testing environment setup. By the setup I mean - gathering all tools together in some way to scan the Docker deliverables. First one is based on a GitLab installation, second is based on a shell script and the last one is relying on a Docker container with all the tools. Yes. A docker container to scan Docker images You can choose whatever way suits you best and modify it to fit your specific infrastructure or use it for self-education on Docker security tools in CI/CD.

    All necessary files are located in our GitHub repo: https://github.com/Swordfish-Security/docker_cicd
    Just git clone it and proceed with the setup instructions
    GitLab

    Complete GitLab installation and running tools to check some test Dockerfile and randomly chosen Docker image - JuiceShop application from the Docker Hub.

    1. Installing Docker:
    sudo apt-get update && sudo apt-get install docker.io
    2. Adding current user into the docker group, so that we won't need sudo to run docker:
    sudo addgroup <username> docker
    3. Finding our IP:
    ip addr
    4. Pulling and running GitLab in a container (substitute IP with your own):
    docker run --detach \
    -- hostname 192.168.1.112 \
    --publish 443:443 --publish 80:80 \
    --name gitlab \
    --restart always \
    --volume /srv/gitlab/config : /etc/gitlab \
    --volume /srv/gitlab/logs : /var/log/gitlab \
    --volume /srv/gitlab/data : /var/opt/gitlab \
    gitlab /gitlab-ce :latest
    Now we have to wait some time until GitLab does the installation magic. Meanwhile you can peek into what it is up to by looking at its logs: docker logs -f gitlab.

    5. Open your local IP in a browser. You would get a Change root password page:
    Change the password and login into GitLab

    6. Create a new project (e.g. cicd-test) and init it with README.md file
    7. Now we should install the Runner, which will run all necessary instruction and tools.
    Downloading the latest version (e.g. for Linux 64-bit):
    sudo curl -L --output /usr/local/bin/gitlab-runner https: //gitlab-runner-downloads .s3.amazonaws.com /latest/binaries/gitlab-runner-linux-amd64
    8. Make it executable:
    sudo chmod +x /usr/local/bin/gitlab-runner
    9. Add a new user for the Runner and start the Runner service:
    sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
    sudo gitlab-runner install --user=gitlab-runner --working-directory= /home/gitlab-runner
    sudo gitlab-runner start
    You should see the following:
    local @osboxes:~$ sudo gitlab-runner install --user=gitlab-runner --working-directory= /home/gitlab-runner
    Runtime platform arch=amd64 os=linux pid=8438 revision=0e5417a3 version=12.0.1
    local @osboxes:~$ sudo gitlab-runner start
    Runtime platform arch=amd64 os=linux pid=8518 revision=0e5417a3 version=12.0.1
    10. Now we shouel register the Runner, so that it could interact with the GitLab instance.
    To do that - open the following page: http://<OUR IP ADDRESS>/root/cicd-test/-/settings/ci_cd , go to the Runners tab and locat URL and Registration token parameters.
    11. Register the Runner substituting URL and Registration token.
    We are passing the --docker-privileged flag to be able to run Docker from the GitLab docker container Runner.
    sudo gitlab-runner register \
    --non-interactive \
    --url "http://<URL>/" \
    --registration-token "<Registration Token>" \
    --executor "docker" \
    --docker-privileged \
    --docker-image alpine:latest \
    --description "docker-runner" \
    --tag-list "docker,privileged" \
    --run-untagged= "true" \
    --locked= "false" \
    --access-level= "not_protected"
    12. Now we are going to add the following file into our GitLab repository - mydockerfile.df (which is a test Dockerfile, that will be analysed) and a configuration file for the GitLab CI/CD process called .gitlab-cicd. - Note the period in its name.
    YAML configuration file contains instructions on running our three tools - Hadolint, Dockle и Trivy, which will analyse the Dockerfile and an image, passed int the DOCKERFILE environment variable.
    You can also scan saved images from .tar files but you will need to add specific parameters for the tools in the YAML file. Feel free to use your own Dockerfile and image.

    13. After you have added the files on the CI/CD → Pipelines page you will see the process of execution.
    By default Trivy stops execution once it has found CRITICAL vulnerabilities in the image or dependencies. Hadolint always returns Success during its execution. We have to consider that when building our CI/CD process.
    Execution results could be found:
    1. In the log of each scanning job;
    2. In json files in the artefacts;
    3. In the HTML report


    15. To present the report in a more human-readable way we utilise a small Python tool to convert json into HTML with the defects table. The script runs in its own job and the result is provided in the Artifacts of the report job.
    shell-script

    A complete shell script, that can be run on any clean machine (e.g. VM). It performs the same operations as the Runner above

    Pre-requisites: Docker should be installed and the current user should be in a docker group

    https://raw.githubusercontent.com/Swordfish-Security/docker_cicd/master/docker_sec_check.sh

    The HTML report could be found in ./docker_tools/results.html

    Docker container with all tools

    As an alternative - there are two Dockerfiles to build an image with all the tools and download a vulnerability database. One of the Dockerfiles will build an image to scan an image from the Docker Hub and another one will build an image to scan an image from a .tar file.

    1. Pull the Dockerfile and scripts https://github.com/Swordfish-Security/docker_cicd/tree/master/Dockerfile
    2. Build an image:
    docker build -t dscan -f docker_security.df .
    3. Run the container (pass the environment variable DOCKERIMAGE with the name of the image and mount Dockerfile from our system to /Dockerfile):
    ~/docker_cicd$ docker run --rm -v $(pwd)/results:/results -v $(pwd)/Dockerfile/docker_security.df:/Dockerfile -e DOCKERIMAGE= "bkimminich/juice-shop" dscan:image
    [+] Running Hadolint
    [+] Running Dockle
    [+] Running Trivy
    2019 - 07 -01T14: 59 : 47 .122Z INFO Removing image caches...
    2019 - 07 -01T14: 59 : 58 .774Z INFO Updating vulnerability database...
    2019 - 07 -01T15: 00 : 07 .402Z INFO Detecting Alpine vulnerabilities...
    2019 - 07 -01T15: 00 : 07 .431Z INFO Updating npm Security DB...
    2019 - 07 -01T15: 00 : 10 .068Z INFO Detecting npm vulnerabilities...
    2019 - 07 -01T15: 00 : 10 .074Z INFO Updating npm Security DB...
    2019 - 07 -01T15: 00 : 10 .990Z INFO Detecting npm vulnerabilities...
    2019 - 07 -01T15: 00 : 11 .017Z INFO Updating vulnerability database...
    2019 - 07 -01T15: 00 : 12 .197Z WARN You should avoid using the :latest tag as it is cached. You need to specify '--clear-cache' option when :latest image is changed
    2019 - 07 -01T15: 00 : 17 .228Z INFO Detecting Alpine vulnerabilities...
    2019 - 07 -01T15: 00 : 17 .267Z INFO Updating npm Security DB...
    2019 - 07 -01T15: 00 : 17 .563Z INFO Detecting npm vulnerabilities...
    2019 - 07 -01T15: 00 : 17 .569Z INFO Updating npm Security DB...
    2019 - 07 -01T15: 00 : 17 .857Z INFO Detecting npm vulnerabilities...

    bkimminich/juice-shop (alpine 3.9.4 )
    ====================================
    Total: 0 (UNKNOWN: 0 , LOW: 0 , MEDIUM: 0 , HIGH: 0 , CRITICAL: 0 )


    juice-shop/ package -lock.json
    ============================
    Total: 0 (UNKNOWN: 0 , LOW: 0 , MEDIUM: 0 , HIGH: 0 , CRITICAL: 0 )


    juice-shop/frontend/ package -lock.json
    =====================================
    Total: 0 (UNKNOWN: 0 , LOW: 0 , MEDIUM: 0 , HIGH: 0 , CRITICAL: 0 )

    [+] Making the output look pretty
    [+] Starting the main module ============================================================
    [+] Converting JSON results
    [+] Writing results HTML
    [+] Clean exit ============================================================
    [+] Everything is done. Find the resulting HTML report in results.html
    The HTML report will be saved into ./results/results.html on a host system.
    Pavel Kann
    Senior Security Expert
    Swordfish Security