SSL Certificate Expiration Checking

We just had an issue with an expired SSL certificate. Although the customer had a monitoring system in place, this system failed to inform the administrators of the upcoming certificate expiration which the leads to a system downtime this morning.

In order to be independent of the customer monitoring, I created a short Linux shell script which does the certificate checking by itself and sends out a notification mail if the certificate expiration date is less than x days away.

We are running this script every week via a cron job and let us warn 60 days in advance of the expiration date. So hopefully this will not happen again in future …

Here is the code of the script:

#!/bin/bash
##########################################################################################
# check_connections.sh / V1.0 / mu
#
# V1.0:     2019-10-01 - Initial version
#
# Check the expiration date of a server SSL certificate
#
# Usage:
# ./checkSSLExpiration.sh hostname:port warning_days
#
# hostname:port The hostname and the port which should be checked. If no port is specified then 443 will be used
# warning_days  If the certificate will expire in less or equal warning_days a warning will be sent via mail. If parameter not specified 30 days is used
#
# Prerequisites:
# The server where the checks are running need access to the host via the specified port The server also needs to be able to send SMTP mails
# via the SMTP relay configured below.
# It uses OpenSSL to check the certificate and mailx to send notification mails
#
##########################################################################################

# Define some variables
errorCode=0

# Sender Address
# Specify here the sender address of the notification mails
sender="SSL Certificate Notification <noreply@example.org>"

# SMTP gateway 
# Define here the full qualified DNS name of the SMTP gateway which should be used to send notification mails.
smtpmx="smtp.example.org"

# Recipients address where to send notification mails
recipients="user1@example.org user2@example.org"

# Check if at least one parameter is given; if yes, use that as hostName:port
if [ -z "$1" ] 
then
    echo "Usage: ./checkSSLExpiration.sh hostname:port [warning_days]"
    exit 1
else
    hostNameWithPort=$1
fi

hostName=`echo $hostNameWithPort | cut -d: -f 1`
port=`echo $hostNameWithPort | cut -d: -f 2 -s`

# If there is no port number, use 443 as default
if [ "$port" == "" ] 
then
    port="443"
    hostNameWithPort="$hostName:$port"
fi

# Check if a second parameter is given; if yes, use that as warning_days. If not, use 30 days as default
if [ -z "$2" ]
then
    warning_days="30"
else
    warning_days=$2
fi

# Check if certificate can be read; if there is an error, report it and end the script
# Specify a timeout of 5 seconds in case the host does not answer
checkCertificateOk=`timeout 5 openssl s_client -servername $hostName -connect $hostNameWithPort 2>/dev/null <<< "Q"`
if [ $? -gt 0 ]
then
    echo "ERROR - Cannot get certificate. Maybe wrong hostnam or port?"
    exit 1
fi

# Get the expiration date and time for the certificate
expirationdate=`date --date="$( echo | openssl s_client -servername $hostName -connect $hostNameWithPort 2>/dev/null | openssl x509 -noout -enddate  | cut -d= -f 2)"`

# Get the expiration date and time for the certificate as number of seconds
expirationdate_days=`date --date="$( echo | openssl s_client -servername $hostName -connect $hostNameWithPort 2>/dev/null | openssl x509 -noout -enddate  | cut -d= -f 2)"  "+%s"`

# Ge the current date / time as nnumber of seconds
today_days=$(date -d "today" "+%s")

# Calculcate the difference of the two times and convert it to days
numberOfDays=$(( ($expirationdate_days - $today_days)/(60*60*24) ))

# Report the result
echo " "
echo "The certificate of"
echo "   $hostName"
echo "expires on"
echo "   $expirationdate"
echo "which is in $numberOfDays days from now!"

if [ $numberOfDays -gt $warning_days ]
then
    # evertyhing ok, the certificate will expire later than the warning_days
    echo " "
    echo "OK - Expiration date is more than $warning_days days in future."
    echo " "
    errorCode=0
elif [ $numberOfDays -le 0 ]
then
    # Report ERROR as the certificate has already expired
    echo " "
    echo "ERROR - Certificate has expired!"
    echo " "
    errorCode=99
    subject="$hostName - SSL Certificate has expired"
    body="ATTENTION: The certificate of $hostName has expired on $expirationdate!"
else
    # Report WARNING as the certificate will expire within warning_days.
    echo " "
    echo "WARNING - Expiration date is near!"
    echo " "
    errorCode=10
    subject="$hostName - SSL Certificate expires in $numberOfDays days"
    body="ATTENTION: The certificate of $hostName expires on $expirationdate which is in $numberOfDays days from now!"
fi

if [ "$errorCode" -eq 0 ]; then 
    # No errors found. Just end
    exit $errorCode
else
    # Send notification mail
    echo -e $body | /bin/mailx -v -s "$subject" -S smtp=smtp://$smtpmx  -r "$sender" $recipients  >/dev/null 2>&1
    echo "Mail notification sent"
    echo " "
    exit $errorCode
fi
Code language: Bash (bash)
SSL Certificate Expiration Checking