Container image security with Wazuh and Trivy

| by | Wazuh 4.11.0
Post icon

Maintaining the security of containerized environments is an important part of modern IT infrastructure. Vulnerabilities in container images and runtime environments expose organizations to significant risks, which makes proactive vulnerability scanning an essential practice.

Trivy is an open source vulnerability scanner designed for containers, filesystems, and software dependencies. It supports a range of targets including Git repositories, Kubernetes deployments, and programming language dependencies (npm, pip, etc.). 

Integrating Trivy with Wazuh enhances container security by detecting vulnerabilities in images and runtime environments, ensuring safer Kubernetes and Docker deployments. It also strengthens CI/CD pipelines by identifying security risks early in development, preventing vulnerable code from reaching production.

In this blog post, we explore how to leverage Trivy and Wazuh to implement effective container vulnerability scanning.

Infrastructure

To demonstrate the integration of Trivy and Wazuh for container vulnerability scanning, we use the following infrastructure:

  • A pre-built, ready-to-use Wazuh OVA 4.11.0 which includes the Wazuh central components (Wazuh server, Wazuh indexer, and Wazuh dashboard). Follow this guide to download and set up the Wazuh virtual machine.
  • An Ubuntu 24.04 endpoint with Wazuh agent 4.11.0 installed and enrolled to the Wazuh server. We install Trivy version 0.59.1 on this endpoint. 

Configuration

To configure this integration, we perform the following:

On the Ubuntu endpoint:

On the Wazuh server:

On the Wazuh dashboard:

Ubuntu

Perform the following steps on the Ubuntu endpoint.

Install Docker Engine and pull container images

Follow the steps below to install Docker Engine and deploy container images on the Ubuntu endpoint.

Note: You need root user privileges to execute all the commands described below.

1. Update the list of available packages and their versions, and install the cURL package:

# apt update && apt install curl -y

2. Run the following commands to download and run the Docker installation script:

# curl -sSL https://get.docker.com/ | sh

3. Create and switch into a project directory ~/container_env for the container environment using the following command:

# mkdir -p ~/container_env && cd ~/container_env

4. Create a configuration file docker-compose.yml  in the container_env directory:

# touch docker-compose.yml

5. Copy and paste the configuration below into the docker-compose.yml file. This configuration file defines a test environment with three services – a Python (FastAPI) service, a PostgreSQL database, and a Redis cache:

services:
  api:
    image: python:3.9-alpine

  db:
    image: postgres:alpine

  redis:
    image: redis:alpine

Note: You can configure the services further, however in this example, the focus is on pulling the base images python:3.9-alpine, postgres:alpine, and redis:alpine. Trivy will scan these container images for vulnerabilities.

6. Run the command below to pull the container images using Docker Compose:

# docker compose pull

7. Verify that the container images are present:

# docker image ls
REPOSITORY   TAG      	 IMAGE ID   	 CREATED    	  SIZE
Postgres     alpine        2bf60600670f    8 days ago       278MB
Redis        alpine        ee33180a8437    5 weeks ago      41.4MB
Python       3.9-alpine    8831b2c8c07c    2 months ago     49.1MB

Install Trivy

Run the commands below to install Trivy on the Ubuntu endpoint. 

1. Install the required dependencies:

# sudo apt-get install -y wget apt-transport-https gnupg lsb-release

2. Import the Trivy repository key:

# wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null

3. Add the Trivy APT repository:

# echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main" | sudo tee -a /etc/apt/sources.list.d/trivy.list

4. Update package lists:

# sudo apt-get update

5. Install the Trivy package:

# sudo apt-get install trivy

6. Verify that Trivy has been installed:

# trivy --version
Version: 0.59.1

Create a custom bash script and configure the Wazuh Command module

Follow the steps below to create a bash script and configure the Wazuh Command module on the Ubuntu endpoint. The script detects existing container images on the endpoint and runs a vulnerability scan on each image using Trivy. The Wazuh Command module periodically executes the script at predefined intervals. Wazuh monitors the script output and treats it as log content for further analysis. 

1. Create a custom script directory /var/ossec/custom-script/ and create a new file trivy_scan.sh using the following command:

# mkdir /var/ossec/custom-script/ && touch /var/ossec/custom-script/trivy_scan.sh

2. Copy and paste the code below into the /var/ossec/custom-script/trivy_scan.sh file:

#!/bin/bash
# Copyright (C) 2015-2025, Wazuh Inc.

# Directory to save the custom output template
TEMPLATE_DIR="/tmp"
TEMPLATE_FILE="$TEMPLATE_DIR/trivy-custom.tmpl"

# Create the custom output template
cat <<EOL > "$TEMPLATE_FILE"
"Package","Version Installed","Vulnerability ID","Severity"
{{- range \$ri, \$r := . }}
{{- range \$vi, \$v := .Vulnerabilities }}
"{{ $v.PkgName }}","{{$v.InstalledVersion }}","{{ $v.VulnerabilityID }}","{{$v.Severity }}","{{$v.Title }}"
{{- end}}
{{- end }}
EOL

# Retrieve list of container images (including both repository and tag)
images=$(docker images --format "{{.Repository}}:{{.Tag}}")
if [ -z "$images" ]; then
  echo "No images found. Exiting..."
  exit 1
fi

# Loop through each container image and run Trivy scan
for image in $images; do
  # Run Trivy scan on the current image using the custom output template
  trivy_output=$(trivy --scanners vuln i -q --format template --template "@/tmp/trivy-custom.tmpl" "$image")

  # Check if the scan was successful
  if [ $? -ne 0 ]; then
	echo "Error running Trivy scan on image $image. Skipping..."
	continue
  fi
 
  # Process Trivy output for the current image
  while IFS= read -r line; do
	# Prepend image name with "Trivy:", followed by image name and a comma
	formatted_line="Trivy:\"$image\",$line"
	# Print the formatted line with quoted image name
	echo "$formatted_line"
  done <<< "$trivy_output"
done

# Clean up the custom output template
rm -f "$TEMPLATE_FILE"

This script sets up a custom output template for Trivy. Then, it retrieves a list of container images and executes a Trivy scan on each container image. Subsequently, it formats the output by adding “Trivy:” at the start of each line. Finally, it cleans up the temporary output template file.

3. Add the executable permission for the owner and group to the /var/ossec/custom-script/trivy_scan.sh file:

# chmod 750 /var/ossec/custom-script/trivy_scan.sh

4. Change the ownership of the /var/ossec/custom-script/trivy_scan.sh file and the directory where it is located:

# chown root:wazuh /var/ossec/custom-script/ -R

5. Edit the Wazuh agent /var/ossec/etc/ossec.conf file and add the following configuration within the <ossec_config> block:

<!-- Trivy container vulnerability scanner script -->
<wodle name="command">
  <disabled>no</disabled>
  <command>/var/ossec/custom-script/trivy_scan.sh</command>
  <interval>3d</interval>
  <ignore_output>no</ignore_output>
  <run_on_start>yes</run_on_start>
  <timeout>0</timeout>
</wodle>

Where:

  • disabled specifies that the command is set to active.
  • command specifies the location of the trivy_scan.sh script to be executed.
  • interval specifies the time interval for the execution of the configured script. In this blog post, the set value executes the trivy_scan.sh every 3 days. Set this value to your preferred time interval.
  • ignore_output determines whether the output of the command execution should be ignored. Setting it to no means that the output will be processed and logged by Wazuh.
  • run_on_start specifies that the Wazuh Command module configuration for the trivy_scan.sh script runs immediately after the Wazuh agent service starts.
  • timeout sets the timeout option to 0. This means the trivy_scan.sh process will execute without any imposed time restrictions to halt it.

6. Restart the Wazuh agent to apply the above changes:

# systemctl restart wazuh-agent

Wazuh server

Create custom decoders and rules

Perform the steps below on the Wazuh server to create and configure custom decoders and rules for processing and monitoring logs generated from the Trivy scan.

Note: You need root user privileges to execute all the commands described below.

1. Create a file trivy_decoders.xml in the /var/ossec/etc/decoders/ directory.

# touch /var/ossec/etc/decoders/trivy_decoders.xml

2. Add the following decoders to the /var/ossec/etc/decoders/trivy_decoders.xml file to parse the Trivy logs received from the Wazuh agent:

<decoder name="trivy-decoder">
  <prematch>^Trivy:</prematch>
</decoder>

<decoder name="trivy-decoder-fields">
  <parent>trivy-decoder</parent>
  <regex offset="after_parent">"(\.+)","(\.+)","(\.+)","(\.+)","(\.+)","(\.+)"</regex>
  <order>image, package, version, vulnerability_id, severity, description</order>
</decoder>

3. Create a file trivy_rules.xml in the /var/ossec/etc/rules/ directory:

# touch /var/ossec/etc/rules/trivy_rules.xml

4. Add the following Wazuh rules to the /var/ossec/etc/rules/trivy_rules.xml file to detect the Trivy scan results:

<group name="trivy,">
  <!-- Parent Rule for Trivy alerts -->
  <rule id="100201" level="0">
	<decoded_as>trivy-decoder</decoded_as>
	<description>Trivy alert detected.</description>
  </rule>

  <!-- This rule detects a critical severity vulnerability in a container image -->
  <rule id="100202" level="14">
	<if_sid>100201</if_sid>
	<field name="severity">CRITICAL</field>
	<description>Trivy alert [CRITICAL]: Vulnerabilty '$(vulnerability_id)' detected in package '$(package)' version '$(version)' on container image '$(image)'.</description>
  </rule>

  <!-- This rule detects a high severity vulnerability in a container image -->
  <rule id="100203" level="12">
	<if_sid>100201</if_sid>
	<field name="severity">HIGH</field>
	<description>Trivy alert [HIGH]: Vulnerabilty '$(vulnerability_id)' detected in package '$(package)' version '$(version)' on container image '$(image)'.</description>
  </rule>

  <!-- This rule detects a medium severity vulnerability in a container image -->
  <rule id="100204" level="7">
	<if_sid>100201</if_sid>
	<field name="severity">MEDIUM</field>
	<description>Trivy alert [MEDIUM]: Vulnerabilty '$(vulnerability_id)' detected in package '$(package)' version '$(version)' on container image '$(image)'.</description>
  </rule>

  <!-- This rule detects a low severity vulnerability in a container image -->
  <rule id="100205" level="4">
	<if_sid>100201</if_sid>
	<field name="severity">LOW</field>
	<description>Trivy alert [LOW]: Vulnerabilty '$(vulnerability_id)' detected in package '$(package)' version '$(version)' on container image '$(image)'.</description>
  </rule>

  <!-- This rule detects an unknown severity vulnerability in a container image -->
  <rule id="100206" level="7">
	<if_sid>100201</if_sid>
	<field name="severity">UNKNOWN</field>
	<description>Trivy alert [UNKNOWN]: Vulnerabilty '$(vulnerability_id)' detected in package '$(package)' version '$(version)' on container image '$(image)'.</description>
  </rule>
</group>

Where:

  • Rule ID 100201 detects the output of the Trivy vulnerability scan. This rule will not generate alerts on the Wazuh dashboard, because, by default, alerts with levels below 3 do not appear on the Wazuh dashboard.
  • Rule ID 100202 detects critical severity vulnerabilities from the Trivy scan.
  • Rule ID 100203 detects high severity vulnerabilities from the Trivy scan.
  • Rule ID 100204 detects medium severity vulnerabilities from the Trivy scan.
  • Rule ID 100205 detects low severity vulnerabilities from the Trivy scan.
  • Rule ID 100206 detects vulnerabilities with unknown severity ratings from the Trivy scan.

5. Modify the ownership and permissions for the trivy_decoders.xml and trivy_rules.xml:

# chown wazuh:wazuh /var/ossec/etc/rules/trivy_rules.xml /var/ossec/etc/decoders/trivy_decoders.xml
# chmod 660 /var/ossec/etc/rules/trivy_rules.xml /var/ossec/etc/decoders/trivy_decoders.xml

6. Restart the Wazuh manager to apply the above changes:

# systemctl restart wazuh-manager

Wazuh dashboard

We perform the following to visualize the Trivy vulnerability alerts on the Wazuh dashboard:

Creating Discover searches on the Wazuh dashboard  

Perform the following steps to view the alerts and create Discover searches on the Wazuh dashboard.

1. Navigate to Explore > Discover.

2. Type rule.groups:trivy in the filter bar and hit the Enter button on your keyboard. 

3. Under Available fields on the left pane, add the following fields as columns by hovering over each field and clicking the + icon beside it: agent.name, data.image, data.vulnerability_id, data.severity, data.package, data.version, and data.description.

4. Click Save in the top right to save the query and enter “Trivy vulnerabilities” in the Title textbox.

Note: If you do not see the fields under Available fields, refresh the fields list from the Index Patterns page. To do this, navigate to Dashboard management > Dashboards Management > Index Patterns. Select wazuh-alerts-* from the list then click the refresh icon ⟳.

Create discover searches

We filter further to identify and visualize alerts for each vulnerability severity.

Critical vulnerability alerts

Perform the following steps to view the critical severity vulnerability alerts on the Wazuh dashboard.

1. Navigate to Explore > Discover.

2. Type rule.groups:trivy and rule.id:100202 in the filter bar and click Update

3. Under Available fields on the left pane, add the following fields as columns by hovering over each field and clicking the + icon beside them: agent.name, data.image, data.vulnerability_id, data.severity, data.package, data.version, and data.description.

4. Click Save in the top right to save the query and enter “Trivy [Critical vulnerabilities]” in the Title textbox.

Critical Vulnerability alerts

High vulnerability alerts

Perform the following steps to view the high severity vulnerability alerts on the Wazuh dashboard.

1. Navigate to Explore > Discover.

2. Type rule.groups:trivy and rule.id:100203 in the filter bar and click Update

3. Under Available fields on the left pane, add the following fields as columns by hovering over each field and clicking the + icon beside them: agent.name, data.image, data.vulnerability_id, data.severity, data.package, data.version, and data.description.  

4. Click Save in the top right to save the query and enter “Trivy [High vulnerabilities]” in the Title textbox.

High Vulnerability alerts

Medium vulnerability alerts

Perform the following steps to view the medium severity vulnerability alerts on the Wazuh dashboard.

1. Navigate to Explore > Discover.

2. Type rule.groups:trivy and rule.id:100204 in the filter bar and click Update

3. Under Available fields on the left pane, add the following fields as columns by hovering over each field and clicking the + icon beside them: agent.name, data.image, data.vulnerability_id, data.severity, data.package, data.version, and data.description.  

4. Click Save in the top right to save the query and enter “Trivy [Medium vulnerabilities]” in the Title textbox.

Medium Vulnerability alerts

Low vulnerability alerts

Perform the following steps to view the low severity vulnerability alerts on the Wazuh dashboard.

1. Navigate to Explore > Discover.

2. Type rule.groups:trivy and rule.id:100205 in the filter bar and click Update

3. Under Available fields, add the following fields as columns by hovering on each field agent.name, data.image, data.vulnerability_id, data.severity, data.package, data.version, and data.description and clicking the + icon beside it.  

4. Click Save in the top right to save the query and enter “Trivy [Low vulnerabilities]” in the Title textbox.

Low Vulnerability alerts

Unknown vulnerability alerts

Perform the following steps to view the unknown severity vulnerability alerts on the Wazuh dashboard.

1. Navigate to Explore > Discover.

2. Type rule.groups:trivy and rule.id:100206 in the filter bar and click Update

3. Under Available fields on the left pane, add the following fields as columns by hovering over each field and clicking the + icon beside them: agent.name, data.image, data.vulnerability_id, data.severity, data.package, data.version, and data.description.  

4. Save the query as “Trivy [Unknown severity vulnerabilities]”. 

Note: Sometimes Trivy generates vulnerabilities with “unknown” severity. This can arise from incomplete data, zero-day vulnerabilities, or differing vendor classifications and does not mean no risk exists. Investigate these findings using the provided details (ID, package, version) to assess potential impact.

Create visualizations

Perform the following steps to create visualizations that will be used to create custom dashboards. We create a pie chart visualization and a vertical bar visualization. 

Pie chart

1. Navigate to Explore > Visualize.

2. Click Create new visualization or Create visualization and select the Pie visualization format. Select Trivy vulnerabilities.

3. Set the following value in the Data section, on the Slice size, in Metrics:

  • Aggregation = Count

4. Add a Split slices in Bucket and set the following values:

  • Aggregation = Terms
  • Field = data.severity
  • Order by = Metric: Count
  • Order = Descending
  • Size = 10

5. Customize the pie chart by toggling on show label in the Options section.

6. Click the Update button.

7. Click save and save as “Trivy container vulnerabilities overview”.

Container Image Security pie chart

Vertical bar

1. Navigate to Explore > Visualize.

2. Click Create visualization and select the Vertical bar visualization format. Select Trivy vulnerabilities.

2. Set the following value in the Data section, on the Y-axis, in Metrics:

  • Aggregation = Count

3. Add an X-axis in Buckets and set the following values:

  • Aggregation = Terms
  • Field = data.image
  • Order by = Metric: Count
  • Order = Descending
  • Size = 10

4. Customize the Vertical bar by toggling on the Show values on chart in the Panel settings section.

5. Click the Update button.

6. Click Save and save as “Vulnerabilities by container image overview”.

Container Image Security vertical bar

Creating custom dashboards

Create a custom dashboard using the pie chart and vertical bar visualizations. 

1. Navigate to Explore > Dashboards > Create New Dashboard.

2. Select Add an existing link and click the saved visualizations (Trivy container vulnerabilities overview and Vulnerabilities by container image overview). This will add the visualizations to the new dashboard.

3. Save the dashboard as “Trivy container image vulnerabilities dashboard”.

Container Image Security creating custom dashboards

Next, we create another dashboard that contains the Discover searches we created previously. 

1. Navigate to Explore > Dashboards > Create New Dashboard.

2. Select Add an existing link and click the saved visualizations (Trivy [Critical vulnerabilities], Trivy [High vulnerabilities], Trivy [Medium vulnerabilities], Trivy [Low vulnerabilities]). This will add the visualizations to the new dashboard. Follow this link to create the visualizations

3. Save the dashboard as “Trivy container image vulnerabilities”.

Container Image discover searches

Conclusion

By combining the vulnerability scanning capabilities of Trivy with the monitoring and alerting features of Wazuh, organizations can strengthen security in containerized environments. This integration not only helps identify and mitigate risks but also makes security an integral part of development and deployment. With automated scans and centralized visibility through the Wazuh dashboard, teams can proactively address threats and maintain a secure CI/CD pipeline.

Wazuh offers container security capabilities that when used with a container image scanning tool like Trivy, provide a comprehensive approach to securing containerized workloads. To learn more about Wazuh, explore our other blog posts and join the growing community.

References