From d2d4bb730a31ec14b88f51397b805b4241686d4c Mon Sep 17 00:00:00 2001 From: Paulo Nonato Date: Sat, 18 Apr 2026 23:31:23 -0300 Subject: [PATCH] Add scripts/tls_certificate_check.sh --- scripts/tls_certificate_check.sh | 87 ++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 scripts/tls_certificate_check.sh diff --git a/scripts/tls_certificate_check.sh b/scripts/tls_certificate_check.sh new file mode 100644 index 0000000..3ccac02 --- /dev/null +++ b/scripts/tls_certificate_check.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +# +# Check HTTPS certificate expiration for one or more domains. +# +# This script is suitable for manual audits or scheduled checks. It exits with +# code 2 when any certificate expires within the warning threshold. +# +# Usage: +# bash tls_certificate_check.sh git.elevartech.com.br +# bash tls_certificate_check.sh --warning-days 30 example.com api.example.com +# +# Options: +# --warning-days N Warn when a certificate expires in N days or less. Default: 21. +# --port N TLS port to check. Default: 443. +# --help Show this help message. + +set -Eeuo pipefail + +warning_days="21" +port="443" +domains=() + +usage() { + sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//' +} + +while [[ "$#" -gt 0 ]]; do + case "$1" in + --warning-days) + warning_days="${2:-}" + [[ "$warning_days" =~ ^[0-9]+$ ]] || { printf 'ERROR: --warning-days must be an integer.\n' >&2; exit 1; } + shift 2 + ;; + --port) + port="${2:-}" + [[ "$port" =~ ^[0-9]+$ ]] || { printf 'ERROR: --port must be an integer.\n' >&2; exit 1; } + shift 2 + ;; + --help|-h) + usage + exit 0 + ;; + *) + domains+=("$1") + shift + ;; + esac +done + +command -v openssl >/dev/null 2>&1 || { printf 'ERROR: openssl command not found.\n' >&2; exit 1; } +[[ "${#domains[@]}" -gt 0 ]] || { printf 'ERROR: at least one domain is required.\n' >&2; usage >&2; exit 1; } + +now_epoch="$(date +%s)" +warning_seconds="$((warning_days * 86400))" +status=0 + +for domain in "${domains[@]}"; do + certificate_end_date="$( + printf '' \ + | openssl s_client -servername "$domain" -connect "${domain}:${port}" 2>/dev/null \ + | openssl x509 -noout -enddate 2>/dev/null \ + | sed 's/^notAfter=//' + )" + + if [[ -z "$certificate_end_date" ]]; then + printf 'CRITICAL: %s:%s certificate could not be read.\n' "$domain" "$port" + status=2 + continue + fi + + end_epoch="$(date -d "$certificate_end_date" +%s)" + seconds_left="$((end_epoch - now_epoch))" + days_left="$((seconds_left / 86400))" + + if [[ "$seconds_left" -le 0 ]]; then + printf 'CRITICAL: %s certificate expired on %s.\n' "$domain" "$certificate_end_date" + status=2 + elif [[ "$seconds_left" -le "$warning_seconds" ]]; then + printf 'WARNING: %s certificate expires in %s days on %s.\n' "$domain" "$days_left" "$certificate_end_date" + status=2 + else + printf 'OK: %s certificate expires in %s days on %s.\n' "$domain" "$days_left" "$certificate_end_date" + fi +done + +exit "$status" +