How to Integrate testssl.sh with Nagios and Icinga for Automated TLS Monitoring

testssl.sh integrates with Nagios and Icinga through dedicated plugins that translate its exit codes and JSON/CSV output into monitoring service states, enabling automated TLS health checks and vulnerability alerting.

The drwetter/testssl.sh repository provides a pure Bash TLS scanner that supports seamless testssl.sh Nagios Icinga integration through wrapper plugins and standardized exit codes. By leveraging the tool's machine-readable output formats and documented ERR_* constants, security teams can automate SSL/TLS certificate and configuration monitoring within existing infrastructure without modifying the core scanner.

Understanding the Integration Architecture

Exit Codes and Machine-Readable Output

The core testssl.sh script defines specific exit codes (documented in doc/testssl.1.md and implemented in testssl.sh via ERR_* constants) that indicate scan status: 0 for success/no findings, 1 for minor issues, 2 for severe vulnerabilities, and higher values for fatal errors. Monitoring plugins map these numeric exit codes to service states (OK, WARNING, CRITICAL, UNKNOWN).

Output Formats for Parsing

The scanner supports --jsonfile and --csvfile flags (defined in testssl.sh command-line parsing) to generate structured data. Plugins parse these files to extract specific vulnerability IDs, certificate expiration dates, and cipher suite ratings, providing granular alert context beyond simple pass/fail status.

Available Monitoring Plugins

Nagios Python Plugin

The official Nagios integration is available via dnmvisser/nagios-testssl, a Python 3 plugin that wraps testssl.sh execution. It translates JSON output and exit codes into Nagios-compliant status messages and performance data.

Icinga 2 Bash Wrapper

For Icinga 2 environments, the check_testssl.sh Bash script (maintained at gitgud.malvager.net/Wazakindjes/icinga2_plugins) provides native integration. It handles argument passing, temporary file management for JSON output, and exit code mapping to Icinga service states.

Implementation Guide

Configuring the Nagios Plugin

Install the Python plugin in your Nagios libexec directory, then define the command and service objects in your configuration files.

Example commands.cfg definition:

define command{
    command_name    check_testssl
    command_line    /usr/local/nagios/libexec/check_testssl.py -H $HOSTADDRESS$ -p $ARG1$
}

Example service definition:

define service{
    use                     generic-service
    host_name               web01.example.com
    service_description     TLS Scan
    check_command           check_testssl!443
}

Setting Up the Icinga 2 Command

Define the CheckCommand object in Icinga 2's commands.conf and apply the service in services.conf.

Example commands.conf:

object CheckCommand "check_testssl" {
  command = [ "/usr/lib/icinga2/plugins/check_testssl.sh" ]
  arguments = {
    "-H" = "$address$"
    "-p" = "$testssl_port$"
    "--jsonfile" = "/var/tmp/testssl-${host.name}-${testssl_port}.json"
  }
}

Example services.conf:

object Service "testssl" {
  host_name = "mail.example.com"
  check_command = "check_testssl"
  vars.testssl_port = "25"
}

Direct Integration Without Wrappers

For custom monitoring solutions or lightweight setups, invoke testssl.sh directly and map its exit codes.

Example Bash wrapper script:

#!/usr/bin/env bash
HOST="example.com"
PORT=443

# Run testssl.sh and capture exit status

/testssl.sh --quiet -p -s -P -f -S -h -U -q --ip=one --color 0 "$HOST:$PORT"
RET=$?

# Map exit codes to monitoring states

case $RET in
    0)  STATE=0; MSG="OK – TLS scan passed" ;;
    1)  STATE=1; MSG="WARNING – Minor issues detected" ;;
    2)  STATE=2; MSG="CRITICAL – Severe vulnerabilities found" ;;
    *)  STATE=3; MSG="UNKNOWN – Unexpected exit code $RET" ;;
esac

echo "$MSG"
exit $STATE

Key Files and Exit Code Reference

Understanding the core files helps troubleshoot integration issues:

File Role Location
testssl.sh Core scanner containing ERR_* exit code constants and output formatting logic Repository root
doc/testssl.1.md Man page documenting --jsonfile, --csvfile, and exit code semantics doc/ directory
Readme.md Lists official third-party plugins and integration hints Repository root
utils/ Helper scripts for OpenSSL compilation (useful if monitoring hosts need specific OpenSSL versions) utils/ directory

Exit code mapping for monitoring integration:

  • 0: OK – No findings or informational results only
  • 1: WARNING – Minor issues detected (e.g., deprecated protocols)
  • 2: CRITICAL – Severe vulnerabilities found (e.g., Heartbleed, CRIME)
  • 3+: UNKNOWN – Scan errors or fatal conditions

Summary

  • testssl.sh Nagios Icinga integration relies on wrapper plugins that translate the scanner's exit codes and structured output into monitoring service states.
  • The Nagios Python plugin (dnmvisser/nagios-testssl) and Icinga 2 Bash wrapper (check_testssl.sh) are the officially referenced integrations listed in the repository's Readme.md.
  • Exit code mapping (0=OK, 1=WARNING, 2=CRITICAL) is defined in testssl.sh via ERR_* constants and documented in doc/testssl.1.md.
  • Machine-readable output via --jsonfile and --csvfile enables granular alerting on specific vulnerabilities, certificate expiration, and cipher suite ratings.
  • Direct integration is possible by invoking testssl.sh from custom scripts and mapping the numeric exit codes to monitoring system states.

Frequently Asked Questions

Does testssl.sh require modification to work with Nagios or Icinga?

No modification of the core testssl.sh script is required. The integration works through external wrapper plugins that execute the scanner as a subprocess and translate its standardized exit codes and JSON/CSV output into the monitoring system's native service states. The repository's Readme.md explicitly lists these third-party plugins as the recommended integration method.

What exit codes does testssl.sh return for monitoring systems?

The scanner returns numeric exit codes defined by ERR_* constants in testssl.sh: 0 indicates success or informational findings only, 1 indicates minor issues (WARNING state), 2 indicates severe vulnerabilities (CRITICAL state), and values 3 or higher indicate scan errors or fatal conditions (UNKNOWN state). These codes are documented in doc/testssl.1.md and map directly to Nagios and Icinga service state conventions.

Can I monitor specific TLS vulnerabilities rather than just pass/fail status?

Yes, by using the --jsonfile or --csvfile output options documented in testssl.sh and doc/testssl.1.md. Monitoring plugins parse these structured files to extract specific vulnerability IDs (such as Heartbleed, CRIME, or BEAST), certificate expiration dates, and cipher suite ratings. This allows for granular service checks that can trigger different alert thresholds based on the severity of specific findings rather than relying solely on the aggregate exit code.

Is there a performance overhead when running testssl.sh from monitoring systems?

The overhead is minimal because testssl.sh is a pure Bash script that executes efficiently against target hosts. However, full TLS scans can take 30-60 seconds depending on network latency and the number of checks enabled (protocols, cipher suites, vulnerabilities). For monitoring purposes, you can optimize performance by restricting scans to specific checks using flags like -p (protocols), -s (cipher suites), or -H (HEARTBLEED only) as documented in doc/testssl.1.md, reducing execution time to 5-10 seconds per host.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →