DEV Community

Cover image for Solved: Monitor Docker Image Vulnerabilities with Trivy and Jenkins
Darian Vance
Darian Vance

Posted on • Originally published at wp.me

Solved: Monitor Docker Image Vulnerabilities with Trivy and Jenkins

🚀 Executive Summary

TL;DR: Automating Docker image vulnerability scanning is essential to mitigate security risks in containerized applications. This guide details integrating Trivy, a fast open-source scanner, with Jenkins CI/CD pipelines to automatically detect and fail builds based on critical vulnerabilities, shifting security left in the development process.

🎯 Key Takeaways

  • Integrating Trivy into a Jenkins pipeline enables automated scanning of Docker images for vulnerabilities, providing immediate security feedback within the CI/CD process.
  • The trivy image –exit-code 1 –severity HIGH,CRITICAL command is crucial for configuring Jenkins to fail builds automatically upon detecting high or critical vulnerabilities.
  • Generating and archiving a JSON scan report (trivy image –format json –output scan-report.json) ensures comprehensive auditing and traceability of vulnerability findings, even if the build fails.

Monitor Docker Image Vulnerabilities with Trivy and Jenkins

Introduction

In the modern software development lifecycle, containerization with Docker has become the standard for building and deploying applications. While containers offer portability and consistency, they also introduce a new layer of security concerns. An image built from a vulnerable base image or containing outdated packages can expose your entire application to significant risks. Manually tracking these vulnerabilities is impractical and error-prone.

This is where automated security scanning becomes essential. By integrating a vulnerability scanner directly into your Continuous Integration/Continuous Deployment (CI/CD) pipeline, you can “shift left,” catching security issues early in the development process. This tutorial provides a comprehensive guide on integrating Trivy, a simple and fast open-source vulnerability scanner, with Jenkins to automate Docker image scanning. By the end, you’ll have a pipeline that automatically scans your images and can fail a build if critical vulnerabilities are detected, ensuring a more secure deployment process.

Prerequisites

Before you begin, ensure you have the following set up and configured:

  • A running Jenkins instance with the Pipeline plugin installed.
  • A Jenkins agent (or the main Jenkins instance) with Docker installed and running.
  • Appropriate permissions for the Jenkins user to execute Docker commands. Typically, this involves adding the ‘jenkins’ user to the ‘docker’ group.
  • A Docker image to scan, either locally built or hosted in a registry like Docker Hub. For this tutorial, we will use a public image for demonstration.

Step-by-Step Guide

Step 1: Install Trivy on Your Jenkins Agent

First, Trivy must be available on the Jenkins agent where your pipeline stages will execute. Trivy is a single binary, which makes installation straightforward. We will download the latest release from its official repository and place it in a directory that is part of the system’s PATH, like a user’s local bin directory.

You can add a “Setup” stage in your Jenkins pipeline to perform this installation on-the-fly, or you can pre-install it on your agent machine. Here is a command to install Trivy on a Linux-based agent:

# Bash Script
# This script downloads and installs Trivy into a user-accessible binary directory.
# Replace VERSION and ARCH with the appropriate values for your system.

export TRIVY_VERSION="0.48.1"
export ARCH="64bit"
export OS="Linux"

# Download the tarball
curl -LO https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_${OS}-${ARCH}.tar.gz

# Extract and install
tar zxvf trivy_${TRIVY_VERSION}_${OS}-${ARCH}.tar.gz
install trivy /home/jenkins/bin/trivy
Enter fullscreen mode Exit fullscreen mode

Explanation: This script downloads the specified Trivy version, extracts the binary from the archive, and then uses the install command to place it in /home/jenkins/bin/. Ensure this directory is included in your Jenkins user’s $PATH environment variable so the trivy command can be called directly.

Step 2: Create a New Jenkins Pipeline Job

Now, let’s create a Jenkins job that will orchestrate the image build and scan process. In your Jenkins dashboard:

  1. Click on New Item.
  2. Enter a name for your job (e.g., “docker-vulnerability-scan”).
  3. Select Pipeline and click OK.
  4. Scroll down to the Pipeline section. You can write your script directly in the text area (choosing “Pipeline script”) or pull it from a Jenkinsfile in your SCM.

For this tutorial, we will use the “Pipeline script” option and paste our script directly into the Jenkins UI.

Step 3: Define the Pipeline with a Trivy Scan Stage

The core of our automation is the Jenkinsfile. This declarative pipeline script defines all the stages our CI process will execute. We will include a placeholder “Build” stage and a dedicated “Vulnerability Scan” stage.

Copy the following pipeline script into your Jenkins job configuration:

// Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any

    environment {
        // Define the image to scan. This can be parameterized.
        DOCKER_IMAGE = 'python:3.9-slim'
    }

    stages {
        stage('Pull Image for Scanning') {
            steps {
                script {
                    echo "Pulling image: ${DOCKER_IMAGE}"
                    sh "docker pull ${DOCKER_IMAGE}"
                }
            }
        }

        stage('Vulnerability Scan') {
            steps {
                script {
                    echo "Scanning ${DOCKER_IMAGE} for vulnerabilities..."
                    // Fail the build if any HIGH or CRITICAL vulnerabilities are found.
                    // The --exit-code flag is crucial for pipeline control.
                    sh "trivy image --exit-code 1 --severity HIGH,CRITICAL ${DOCKER_IMAGE}"
                }
            }
        }

        stage('Generate and Archive Report') {
            steps {
                script {
                    echo "Generating JSON report for ${DOCKER_IMAGE}..."
                    // Generate a report regardless of vulnerabilities for auditing.
                    // The '|| true' ensures this step doesn't fail the pipeline if Trivy returns a non-zero exit code.
                    sh "trivy image --format json --output scan-report.json ${DOCKER_IMAGE} || true"
                }
                archiveArtifacts artifacts: 'scan-report.json', allowEmptyArchive: true
            }
        }
    }

    post {
        always {
            echo 'Scan complete. Cleaning up...'
            // Clean up the downloaded image to save space on the agent.
            sh "docker rmi ${DOCKER_IMAGE} || true"
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Explanation of the Jenkinsfile:

  • agent any: This tells Jenkins to run the pipeline on any available agent.
  • environment: We define the DOCKER\_IMAGE variable here. In a real-world scenario, this would likely be the image you just built (e.g., my-app:1.2.${env.BUILD\_NUMBER}).
  • stage(‘Pull Image for Scanning’): Before scanning, we ensure the image is available on the agent by pulling it from a registry. If you were building the image in a previous stage, this step would not be necessary.
  • stage(‘Vulnerability Scan’): This is the critical stage.
    • We execute trivy image… as a shell command.
    • –exit-code 1: This tells Trivy to exit with a status code of 1 if any vulnerabilities are found. This non-zero exit code will cause the Jenkins sh step to fail, thereby failing the pipeline stage.
    • –severity HIGH,CRITICAL: We are instructing Trivy to only trigger the non-zero exit code for vulnerabilities classified as HIGH or CRITICAL. You can adjust this to include MEDIUM or LOW as per your security policy.
  • stage(‘Generate and Archive Report’): This stage is for record-keeping.
    • We run the scan again, but this time we format the output as JSON (–format json) and save it to a file.
    • The || true is important here. It ensures that this shell command succeeds even if Trivy finds vulnerabilities and exits with code 1. This allows us to archive the report even if the previous scan stage failed the build.
    • archiveArtifacts: This Jenkins step saves the scan-report.json file with the build record, making it available for download and review from the Jenkins UI.
  • post { always { … } }: The post block runs after all stages are complete. The always condition ensures that we clean up the Docker image from the agent regardless of whether the pipeline succeeded or failed.

Common Pitfalls

1. Docker Command Fails with “Permission Denied”

A frequent issue is that the Jenkins user does not have permission to interact with the Docker daemon. You might see an error like Got permission denied while trying to connect to the Docker daemon socket. This happens because, by default, only the root user and users in the docker group can access the Docker daemon socket.

Solution: You need to add the jenkins user to the docker group on the agent machine. After adding the user to the group, you must restart the Jenkins agent process (or the entire machine) for the new group membership to take effect.

2. Pipeline Fails on Base Image Vulnerabilities

Sometimes, your scan will detect vulnerabilities in the official base image you are using (e.g., python:3.9-slim, node:18-alpine). Often, these vulnerabilities have not yet been patched by the base image maintainers. Continuously failing your build for issues you cannot fix is counterproductive.

Solution: Trivy allows you to ignore specific vulnerabilities. You can create a file named .trivyignore in your project repository and list the CVE IDs you wish to suppress, along with a reason or expiry date. You can then reference this file in your scan command using the –ignorefile flag: trivy image –ignorefile .trivyignore … This practice ensures you are making a conscious decision to accept a risk, rather than letting it block your development pipeline indefinitely.

Conclusion

By integrating Trivy into your Jenkins pipeline, you have built a powerful, automated guardrail for your containerized applications. This setup provides immediate feedback on security vulnerabilities, empowering developers to address issues long before they reach production. Automating security scanning not only strengthens your application’s security posture but also embeds a culture of security-consciousness within your development team. From here, you can expand this pipeline to push reports to a centralized security dashboard, send notifications on critical findings, or even enforce stricter policies based on vulnerability scores.


Darian Vance

👉 Read the original article on TechResolve.blog


☕ Support my work

If this article helped you, you can buy me a coffee:

👉 https://buymeacoffee.com/darianvance

Top comments (0)