Tanúsítvány-ellenőrző

Hátha valakinek hasznos, mert el szokta felejteni a cert-jeit időben frissíteni... (amíg tesztelgettem, találtam egy-két portált, aminek több éve lejárt a cert-je... és még olyat is, ami ezzel együtt cert alapú azonosítást akar...)

Changelog:

2015. 08. 23 22: első verzió
2015. 08. 23 22: VincentV javaslatára SNI support
2015. 08. 24 23: StartTLS support
2015. 08. 24: hrgy84 javaslatára temp fájlok használata, ${valtozo} forma használata, a test jobb paraméterezése; változó inicializálással egy else ág törlése

Valszeg tele van bashism-el, de GNUismmal biztos (a date argumentumai, a timeout stb.), úgyhogy hordozhatóság nulla, de íme:

/usr/bin/certcheck


#!/bin/bash
RECIPIENT="root"
HOSTLIST="/etc/certcheck/hostlist"
SSLTIMEOUT=10

check_cert() {
  host=""
  port=""
  TLS=""
  if [ -z "$1" ]; then
    echo "Empty host name"
    exit
  fi
  host="$1"
  port=443
  if [ -n "$2" ]; then
    port="$2"
  fi
  if [ -n "$3" ]; then
    TLS="-starttls $3"
  fi
  cert_file=$(mktemp)
  if [ $? -ne 0 ]; then
    echo "Could not create temp file for cert download"
    exit
  fi
  echo "QUIT" | timeout ${SSLTIMEOUT} openssl s_client -showcerts -connect ${host}:${port} -servername ${host} ${TLS} > "${cert_file}" 2> /dev/null
  if [ $? -ne 0 ]; then
    echo "Could not fetch certificate for ${host}:${port}"
    exit
  fi
  cert_info=$(mktemp)
  if [ $? -ne 0 ]; then
    echo "Could not create temp file for cert data"
    exit
  fi
  openssl x509 -text -noout -in "${cert_file}" > "${cert_info}"
  if [ $? -ne 0 ]; then
    echo "Could not parse fetched certificate for ${host}:${port}"
    exit
  fi
  date="$(sed -e '/Not After : /!d' -e '/Not After :/s/Not After : //' "${cert_info}")"
  expiry_date=$(date --date="${date}" "+%s")
  curr_date=$(date +"%s")
  difference=$(( ${expiry_date} - ${curr_date} ))
  rm "${cert_file}" "${cert_info}"
  if [ ${difference} -le 0 ]; then
    echo "Certificate expired for ${host}:${port}";
  elif [ ${difference} -le 2592000 ]; then
    echo "Certificate for ${host}:${port} will expire on $(date --date="@${expiry_date}" +"%Y-%m-%d")"
  fi
}

if [ ! -f "${HOSTLIST}" ]; then
  echo "The host list does not exist"
  exit 1
fi

result="$(while read host port proto
do
  check_cert "${host}" "${port}" "${proto}"
done < "${HOSTLIST}")"

if [ -n "${result}" ]; then
  (echo "Subject: Certificate check result"; echo "${result}") | /usr/sbin/sendmail ${RECIPIENT}
fi
exit 0

A $HOSTLIST-ben megadott fájlban soronként kell egy hosztnév, (ha nem https certről van szó) port és ha STARTLS-t kell tesztelni, akkor protokoll (az openssl ezeket támogatja: "smtp", "pop3", "imap", "ftp", "xmpp", and "xmpp-server") hármas, pl.


google.com
bing.com 443
mail.example.com 587 smtp

Csatlakozik az összes megadott hosthoz/porthoz, lekéri a certet, kioperálja belőle a lejárat idejét, ha talál olyat, ami már lejárt, vagy 30 napon belül lejár, akkor a $RECIPIENT-ben megadott e-mail címre kiküld egy levelet az eredménnyel (melyik host melyik portja járt le/fog lejárni) [$SSLTIMEOUT másodpercig vár egy-egy kapcsolódásra]

Bónuszként két systemd unit hozzá, hogy naponta fusson (btw, akinek van tippe, hogy melyik env változó hiányzik a mailx-nek, ha systemd service-ként fut, ne tartsa magában, én meguntam a debugolást)

/etc/systemd/system/certcheck.service


[Unit]
Description=A simple service that checks the certficiates of network services

[Service]
Type=oneshot
ExecStart=/usr/bin/certcheck
User=root

/etc/systemd/system/certcheck.timer


[Unit]
Description=The timer that runs certcheck.service

[Timer]
Persistent=true
OnCalendar=daily

[Install]
WantedBy=timers.target

Egy systemctl enable certcheck.timer && systemctl start certcheck.timer után elvileg aktív.

BlackY

Hozzászólások

Nem rossz, de a timeouttal/dátummal vacakolás helyett én ezt használtam volna:


$ /usr/lib/nagios/plugins/check_http --help | grep -A2 "SSL enabled web server"
 This plugin can also check whether an SSL enabled web server is able to
 serve content (optionally within a specified time) or whether the X509 
 certificate is still valid for the specified number of days.

A manja (és forrás) alapján a nagios plug-in se, ha csak cert-et ellenőriz (-C), akkor a kapcsolódás után bontja a kapcsolatot és kilép. (mondjuk ha nem sikerül neki, akkor a logba HTTP hiba kerül, lehet egy bug reportot megérne ["HTTP CRITICAL - Unable to open TCP socket\n"] :) )

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)

Azért a teljes nagios nem kell, Debianban pl elég a monitoring-plugins-basic, ami 2 MB telepítve és említésre méltó függősége nem igazán van.

Igen, a -C az egy speciális mód, ahogy írja is a help-ben. Persze tud https-t get-elni, de egy körben valóban nem megy a két teszt, bár ez itt szerintem semmit nem vesz el a felhasználhatóságából.

És az SNI-vel mi lesz? :)

... -servername $host

if [ "$1" == "" ]; then

Ne. Tenyleg, ne. Ez annyira nem szep. Tessek elolvasni a 'man test' kimenetet, es rajonni, hogy


  if [ -z "$1" ]; then

Ennek az ellentete pedig:


  if [ -n "$3" ]; then

Az openssl s_client -nel pedig celszeru egybol egy QUIT parancsot echozni, arra ugyanis mindig hiba nelkul lep ki.

Ami pedig a $cert-et illeti..., nos, en nem tarolnek egy komplett certet (cert chain-t) egy darab valtozoban, nem szokott az egeszseges lenni. mktemp, kiiranyitod a temp fajlba a certet es onnantol az 'openssl x509 -text -noout -in ${certfile}' a baratod. Ja, egyebkent a -noout mindig hasznos, ha openssl-lel dolgozol.
--
Blog | @hron84
Üzemeltető macik