X.509 certificate chain monitor for IoT device fleets.
cert-patrol is a command-line tool for monitoring TLS certificate health across distributed IoT device fleets. In industrial IoT deployments — SCADA systems, smart grid controllers, medical devices, connected vehicles — expired or misconfigured certificates cause silent communication failures that are difficult to diagnose at scale.
cert-patrol connects to each device endpoint, extracts the full certificate chain, and validates it against configurable security policies:
- Expiry monitoring — detect certificates expiring within a configurable window
- Chain validation — verify the chain is complete and anchored to a trusted root
- Cryptographic compliance — flag weak RSA keys (<2048-bit), small EC keys (<256-bit), and SHA-1 signatures
- TLS version audit — confirm devices negotiate TLS 1.2 or 1.3, flag deprecated versions
- SAN verification — ensure certificate Subject Alternative Names match the expected hostname
- Cipher suite analysis — classify negotiated cipher suites as strong/acceptable/weak, flag RC4, 3DES, NULL, EXPORT ciphers
- Protocol version detection — check for TLS 1.0/1.1 support, flag deprecated versions
- OCSP and CRL checking — extract OCSP responder URLs, CRL distribution points, check revocation status
- Key usage validation — verify Extended Key Usage matches server/client auth requirements
- Fleet-wide reporting — JSON, CSV, and colored terminal table output for integration with monitoring pipelines
- Continuous monitoring — watch mode with configurable rescan intervals and alert delivery
- Fleet diff — compare reports over time to detect certificate changes, renewals, and expirations
- Certificate inventory — deduplicate certificates across hosts, show which cert is used where
- Alerting — configurable thresholds with file and webhook alert sinks
- Certificate pinning — maintain SPKI hash pins per host, detect unexpected certificate changes
- Prometheus metrics — export fleet health metrics in exposition format for monitoring pipelines
- Host tagging — organize fleet hosts with arbitrary key:value tags for filtering and grouping
- Quiet mode — machine-readable exit-code-only output for CI/CD integration
- Optional TUI dashboard — interactive terminal UI with Ratatui (compile with
--features tui)
cargo install --path .With TUI support:
cargo install --path . --features tuiOr build from source:
cargo build --release
cargo build --release --features tuiCreate a hosts file with one host:port entry per line:
# hosts.txt — production IoT fleet
gateway-01.factory.local:8883
gateway-02.factory.local:8883
scada-controller.plant.local:443
mqtt-broker.edge.local:8883
ota-server.cloud.example.com:443
Scan all hosts with colored output:
cert-patrol scan -f hosts.txtWith options:
cert-patrol scan -f hosts.txt --warn-days 60 --timeout 15 --concurrency 64 --output json# Colored terminal table (default)
cert-patrol scan -f hosts.txt --output table
# JSON output
cert-patrol scan -f hosts.txt --output json
# CSV output for spreadsheet import
cert-patrol scan -f hosts.txt --output csvcert-patrol scan -f hosts.txt --check-ciphersReports each host's negotiated cipher suite with strength classification (STRONG/ACCEPTABLE/WEAK) and flags deprecated TLS protocol versions.
# Group by base domain
cert-patrol scan -f hosts.txt --group-by domain
# Group by certificate issuer
cert-patrol scan -f hosts.txt --group-by issuer
# Group by expiry time range
cert-patrol scan -f hosts.txt --group-by expiryShow deduplicated certificates across the fleet:
cert-patrol scan -f hosts.txt --inventoryRescan the fleet every N minutes, detect status changes, send alerts:
# Rescan every 5 minutes, write alerts to file
cert-patrol scan -f hosts.txt --watch 5 --alert-file /var/log/cert-alerts.log
# Rescan every 10 minutes, send alerts to webhook
cert-patrol scan -f hosts.txt --watch 10 --alert-webhook https://hooks.slack.com/...
# Both file and webhook alerts
cert-patrol scan -f hosts.txt --watch 5 --alert-file alerts.log --alert-webhook https://hooks.example.com/certsCompare two JSON reports to see what changed:
# Generate a baseline report
cert-patrol report -f hosts.txt --json-output baseline.json
# Later, generate a new report and diff against baseline
cert-patrol scan -f hosts.txt --diff baseline.json
# Or diff two saved reports
cert-patrol diff -a baseline.json -b current.json
cert-patrol diff -a baseline.json -b current.json --output jsoncert-patrol check-file -f /etc/ssl/certs/device.pem --hostname gateway-01.factory.localcert-patrol report -f hosts.txt --json-output fleet-report.json
cert-patrol report -f hosts.txt --check-ciphers --group-by issuer --inventoryTrack certificate public key hashes per host. On subsequent scans, cert-patrol alerts if a certificate has changed unexpectedly (potential MITM or unplanned rotation):
# First scan records pins
cert-patrol scan -f hosts.txt --pin-db pins.json
# Subsequent scans compare against stored pins
cert-patrol scan -f hosts.txt --pin-db pins.jsonExport fleet health metrics in Prometheus exposition format for integration with Grafana, Alertmanager, or any Prometheus-compatible monitoring stack:
cert-patrol scan -f hosts.txt --prometheus /var/lib/node_exporter/cert_patrol.promExported metrics include cert_patrol_cert_days_until_expiry, cert_patrol_cert_valid, cert_patrol_tls_version, and fleet-level aggregates.
Organize fleet hosts with tags for filtering and reporting:
cert-patrol scan -f hosts.txt --tag env:prod --tag team:platform --prometheus metrics.promTags are propagated to Prometheus metric labels.
Suppress all output, communicate only via exit codes (useful in CI/CD):
cert-patrol scan -f hosts.txt --quiet
echo $? # 0=ok, 1=warnings, 2=errorsLaunch the terminal dashboard (requires --features tui):
# Via dedicated subcommand
cert-patrol tui -f hosts.txt
# Or via --tui flag on scan
cert-patrol scan -f hosts.txt --tui
# With auto-refresh
cert-patrol tui -f hosts.txt --watch 5TUI keybindings:
q— quitr— rescan fleet/— filter hostsEnter— show certificate detailsEsc— close detail panelTab— switch panel focuss— cycle sort columnj/kor arrows — navigate
Without the tui feature, --tui prints a message to recompile with --features tui.
cert-patrol fleet report | 5 hosts scanned | 2026-04-03 14:22:01 UTC
valid: 3 expiring: 1 expired: 1 warnings: 0 errors: 0
╭──────────────────────────────────┬──────────┬──────────────────────────────┬───────────┬─────────────┬─────────────────────╮
│ Host │ Status │ Subject │ Days Left │ TLS │ Issues │
├──────────────────────────────────┼──────────┼──────────────────────────────┼───────────┼─────────────┼─────────────────────┤
│ gateway-01.factory.local:8883 │ VALID │ CN=gateway-01.factory.local │ 247 │ TLSv1_3 │ none │
│ gateway-02.factory.local:8883 │ EXPIRING │ CN=gateway-02.factory.local │ 12 │ TLSv1_3 │ expires in 12 days │
│ scada-controller.plant.local:443 │ EXPIRED │ CN=scada-controller │ -34 │ TLSv1_2 │ certificate expired │
│ mqtt-broker.edge.local:8883 │ VALID │ CN=mqtt-broker.edge.local │ 364 │ TLSv1_3 │ none │
│ ota-server.cloud.example.com:443 │ VALID │ CN=ota-server.cloud.example │ 180 │ TLSv1_3 │ none │
╰──────────────────────────────────┴──────────┴──────────────────────────────┴───────────┴─────────────┴─────────────────────╯
[#########################...............] 60% healthy
| Code | Meaning |
|---|---|
| 0 | All hosts valid |
| 1 | Expiring certificates or warnings detected |
| 2 | Expired certificates or connection errors |
src/
├── main.rs — CLI entry point, argument parsing, command dispatch
├── models.rs — Data types: CertInfo, ScanResult, FleetReport, ValidationIssue
├── scanner.rs — TLS connection and certificate extraction per host
├── validator.rs — Certificate chain validation, expiry, key size, SAN checks
├── fleet.rs — Fleet-wide concurrent scanning with semaphore control
├── report.rs — JSON and plain table report generation
├── display.rs — Colored terminal output, CSV, grouping, inventory
├── cipher_check.rs — Cipher suite strength analysis, protocol version detection
├── ocsp.rs — OCSP responder/CRL extraction, key usage validation
├── monitor.rs — Continuous monitoring loop with change detection
├── diff.rs — Fleet report diffing (added/removed/renewed/expired)
├── alerts.rs — Alert generation and delivery (file, webhook)
├── pinning.rs — Certificate SPKI pinning database (JSON-backed)
├── prometheus.rs — Prometheus exposition format metrics export
└── tui/ — Optional Ratatui TUI (behind "tui" feature)
├── mod.rs
├── app.rs — Application state and event loop
└── widgets.rs — Widget rendering (summary bar, host table, detail panel)
cert-patrol returns non-zero exit codes suitable for CI/CD pipelines:
# GitLab CI example
cert-check:
stage: security
script:
- cert-patrol scan -f fleet-hosts.txt --warn-days 30 --output json > report.json
- cert-patrol scan -f fleet-hosts.txt --diff baseline.json || true
artifacts:
paths:
- report.json
allow_failure: falseAlerts sent to webhooks are JSON POST requests:
{
"tool": "cert-patrol",
"version": "1.1.0",
"timestamp": "2026-04-03T14:22:01Z",
"severity": "CRITICAL",
"host": "scada-controller.plant.local:443",
"message": "certificate expired",
"details": "expired 34 days ago, subject: CN=scada-controller"
}All configuration is via command-line flags:
| Flag | Default | Description |
|---|---|---|
--warn-days |
30 | Days before expiry to flag as EXPIRING |
--timeout |
10 | Connection timeout in seconds |
--concurrency |
32 | Maximum parallel connections |
--output |
table | Output format: table, json, or csv |
--check-ciphers |
off | Analyze cipher suite strength |
--check-ocsp |
off | Check OCSP revocation status |
--group-by |
none | Group results: domain, issuer, expiry |
--inventory |
off | Show deduplicated certificate inventory |
--watch N |
off | Continuous monitoring every N minutes |
--diff FILE |
none | Compare against previous JSON report |
--alert-file |
none | Write alerts to file |
--alert-webhook |
none | POST alerts to webhook URL |
--pin-db FILE |
none | Certificate pin database file (SPKI hash tracking) |
--prometheus FILE |
none | Export Prometheus exposition format metrics |
--tag KEY:VALUE |
none | Host tag for fleet organization (repeatable) |
--quiet / -q |
off | Suppress output, exit code only |
--tui |
off | Launch interactive TUI (requires --features tui) |
| Feature | Description |
|---|---|
| (default) | Full CLI tool without TUI |
tui |
Enables Ratatui-based interactive terminal dashboard |
Every gateway communicates with the cloud/server via TLS (encrypted connection, like HTTPS). For this, each gateway needs an X.509 certificate — a digital identity card. Yes, each gateway has its own unique certificate (plus the CA certificate that signed it). 4000 gateways = 4000 certificates.
Certificates have an expiration date (typically 1 year). When a certificate expires, the gateway can no longer connect to the server → the client loses telemetry → angry phone call. With 4000 devices, some certificate is always about to expire.
cert-patrol scan --hosts fleet.txt # scan all 4000 hostsResult: a table with every host, certificate status, days until expiry. Red = expired, yellow = expiring within 30 days, green = OK. Webhook to Slack: "Gateway GW-3847 certificate expires in 7 days!" You renew it before anyone notices.
MIT License. Copyright (c) 2026 isecwire GmbH.