Monitoring¶
cron¶
*/15 * * * * certfan check -f /etc/certfan/hosts.txt > /var/log/certfan.log || mail -s "certfan" ops@example.com < /var/log/certfan.log
Prometheus (node_exporter textfile collector)¶
certfan check shop.example.com --prom-file /var/lib/node_exporter/textfile/certfan.prom
Metrics:
certfan_node_cert_expiry_seconds{host,ip,serial}: notAfter as a Unix timecertfan_node_status{host,ip,serial}: 0 pass, 1 warn, 2 failcertfan_node_ocsp_stapled{host,ip,serial}: 1 if the handshake returned an OCSP staplecertfan_node_chain_len{host,ip,serial}: certificates in the presented chain (leaf first)certfan_node_alpn_info{host,ip,serial,alpn}: with--alpn, always 1; the label is the selected protocolcertfan_distinct_certs{host}: should be 1
Mail and database targets go in the same targets file:
# /etc/certfan/hosts.txt
shop.example.com alpn=h2,http/1.1
mx.example.com starttls=smtp
mail.example.com:587 starttls=smtp
mail.example.com:993 # implicit TLS: no starttls
db.internal starttls=postgres warn_days=14
Example alert:
- alert: CertFanOut
expr: certfan_distinct_certs > 1
for: 15m
CI / after a deploy¶
- run: pipx install "git+https://github.com/Blackman99/certfan@v0.3.0"
- run: certfan check shop.example.com --format json > certfan.json
JSON¶
--format json prints a list with one object per target: host, verdict, distinct_certs, checked_at,
nodes[] (ip, port, fingerprint, serial, subject_cn, issuer_cn, sans, not_before, not_after, tls_version, ms,
chain_fingerprints, ocsp_stapled, verify_error, error, status, starttls, banner, alpn, error_stage) and
findings[] (level, ip, message). Hosts checked with --starttls add starttls; with --alpn, alpn_offered.