#!/bin/bash ################################################################################ # Script Name: lynis-metrics-exporter.sh # Version: 1.01 # Description: Prometheus exporter for Lynis security auditing — hardening # index, test pass/fail/skip counts, warnings, suggestions, # component scores, and scan metadata # # Author: Phil Connor # Contact: contact@mylinux.work # Website: https://mylinux.work # License: MIT # # Prerequisites: # - Lynis installed (lynis command available) # - Root/sudo access (Lynis requires root for full audit) # - awk, grep # # Usage: # # Output to stdout # sudo ./lynis-metrics-exporter.sh # # # Textfile collector mode # sudo ./lynis-metrics-exporter.sh --textfile # # # HTTP server mode # sudo ./lynis-metrics-exporter.sh --http -p 9194 # # Metrics Exported: # - lynis_up - Exporter status (1=up, 0=down) # - lynis_exporter_info{version} - Exporter version info # - lynis_hardening_index - Overall hardening score (0-100) # - lynis_tests_performed - Total tests run # - lynis_tests_passed - Tests passed # - lynis_tests_failed - Tests failed # - lynis_tests_skipped - Tests skipped # - lynis_warnings_total - Total warnings # - lynis_suggestions_total - Total suggestions # - lynis_plugins_enabled - Enabled plugins count # - lynis_vulnerable_packages - Packages with known vulnerabilities # - lynis_firewall_active - Firewall detected and active (1/0) # - lynis_malware_scanner - Malware scanner present (1/0) # - lynis_scan_duration_seconds - Lynis audit duration # - lynis_exporter_duration_seconds - Script execution time # - lynis_exporter_last_run_timestamp - Last run timestamp # # Configuration: # Default HTTP port: 9194 # Textfile directory: /var/lib/node_exporter # Lynis report: /var/log/lynis-report.dat # ################################################################################ # ============================================================================ # CONFIGURATION VARIABLES # ============================================================================ TEXTFILE_DIR="/var/lib/node_exporter" OUTPUT_FILE="" HTTP_MODE=false HTTP_PORT=9194 LYNIS_REPORT="/var/log/lynis-report.dat" RUN_AUDIT=false EXPORTER_VERSION="1.0" # ============================================================================ # HELPER FUNCTIONS # ============================================================================ show_usage() { cat <&2; exit 1 ;; esac done } prom_escape() { local val="$1" val="${val//\\/\\\\}" val="${val//\"/\\\"}" val="${val//$'\n'/}" echo "$val" } get_report_value() { local key="$1" grep "^${key}=" "$LYNIS_REPORT" 2>/dev/null | head -1 | cut -d'=' -f2- } count_report_key() { local key="$1" grep -c "^${key}" "$LYNIS_REPORT" 2>/dev/null || true } # ============================================================================ # METRIC GENERATION # ============================================================================ generate_metrics() { local script_start script_start=$(date +%s) # Run audit if requested if [ "$RUN_AUDIT" = true ]; then lynis audit system --quick --no-colors --quiet 2>/dev/null fi # Check if report exists if [ ! -f "$LYNIS_REPORT" ]; then cat </dev/null || true) local tests_passed tests_failed tests_passed=$(grep "^test_result=OK" "$LYNIS_REPORT" 2>/dev/null | wc -l) tests_failed=$(grep "^test_result=WARNING\|^test_result=SUGGESTION\|^test_result=DIFFERENT\|^test_result=WEAK" "$LYNIS_REPORT" 2>/dev/null | wc -l) local tests_skipped_count tests_skipped_count=$(grep -c "^test_skipped=" "$LYNIS_REPORT" 2>/dev/null || true) cat </dev/null; then firewall_active=1 fi if get_report_value "malware_scanner_installed" | grep -qi "1\|yes\|true" 2>/dev/null; then malware_scanner=1 fi vulnerable_packages=$(get_report_value "vulnerable_packages_found") vulnerable_packages=${vulnerable_packages:-0} local plugins_enabled plugins_enabled=$(get_report_value "plugins_enabled") plugins_enabled=${plugins_enabled:-0} cat <&2 if ! command -v nc >/dev/null 2>&1; then echo "ERROR: netcat (nc) required for HTTP mode" >&2 exit 1 fi while true; do { read -r request if [[ "$request" =~ ^GET\ /metrics ]]; then echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/plain; version=0.0.4\r\n\r" generate_metrics else echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r" cat < Lynis Exporter v$EXPORTER_VERSION

Lynis Prometheus Exporter v$EXPORTER_VERSION

Metrics

EOF fi } | nc -l -p "$HTTP_PORT" -q 1 2>/dev/null done } # ============================================================================ # MAIN EXECUTION # ============================================================================ main() { parse_args "$@" if [ "$HTTP_MODE" = true ]; then run_http_server elif [ -n "$OUTPUT_FILE" ]; then local output_dir output_dir="$(dirname "$OUTPUT_FILE")" mkdir -p "$output_dir" local temp_file temp_file=$(mktemp "${output_dir}/.lynis_metrics.XXXXXX") if ! generate_metrics > "$temp_file" 2>/dev/null; then rm -f "$temp_file" echo "ERROR: Failed to generate metrics" >&2 exit 1 fi local file_lines file_lines=$(wc -l < "$temp_file" 2>/dev/null || echo 0) if [ "$file_lines" -lt 5 ]; then rm -f "$temp_file" echo "ERROR: Metrics file too small ($file_lines lines)" >&2 exit 1 fi chmod 644 "$temp_file" mv -f "$temp_file" "$OUTPUT_FILE" echo "Metrics written to $OUTPUT_FILE ($file_lines lines)" >&2 else generate_metrics fi } main "$@"