Check SSL certificate expiration using bash and cURL

I have a few environments where Certbot (and similar) scripts cannot renew SSL certificates without manual intervention, but I still need to know when the certificates are getting close to their expiration date.

This bash script will check a certificate’s expiration date, using cURL, and optionally send you an e-mail if the expiration date is within a given window of days.

 

The script is also available as a gist here:
gist.github.com/joho1968/0441f2c50d26efe784af09193b3ec438

The “bash icon” was sourced here:
hackaday.com/2018/01/19/linux-fu-custom-bash-command-completion/bash-icon/

#!/bin/bash

#
#
# Check expiration date of SSL certificate using cURL
#
# I'm sure there are a million ways to do this better, so feel free to.
# The script is not extremely fault tolerant, but "it works for me" :)
# You may need to --- modify --- this script to suit your environment.
#
# Joaquim Homrighausen, Sweden, some time in 2025
#
# (it's entirely intentional that this script does things in separate
# steps as opposed to a super compact and cryptic way, as is common
# with many bash-ninja-things)
#
#

# Function to show script usage
usage() {
  echo "Usage: $0 -u CHECK_URL -e EXPIRE_DAYS [-a EMAIL_ADDRESS] [-s] [-v]"
  echo " -u CHECK_URL The URL of the site, e.g. https://somesite.somedomain"
  echo " -e EXPIRE_DAYS Warn this many days ahead of expiration"
  echo " -a EMAIL_ADDRESS (Optional) Send expiration warning/notice to this e-mail address"
  echo " -s (Optional) Send e-mail, otherwise just display status"
  echo " -v (Optional) Be somewhat verbose"
  exit 2
}

# Set defaults, etc.
DRY_RUN=true
VERBOSE=false
EXPIRE_DAYS=
EXPIRE_EMAIL=
EXPIRE_URL=

# Parse command line arguments
while getopts "u:e:a:s;v" opt; do
  case $opt in
    u) EXPIRE_URL=$OPTARG ;;
    e) EXPIRE_DAYS=$OPTARG ;;
    a) EXPIRE_EMAIL=$OPTARG ;;
    s) DRY_RUN=false ;;
    v) VERBOSE=true ;;
    *) usage ;;
  esac
done

# Check if all mandatory parameters are provided
if [ -z "${EXPIRE_DAYS}" ] || [ -z "${EXPIRE_URL}" ]; then
  usage
fi
# Check if options require more parameters
if [ "${DRY_RUN}" == false ] && [ -z "${EXPIRE_EMAIL}" ]; then
  echo -e "\n-s requires e-mail address to be specified\n"
  usage
fi

# Fetch certificate information from specified URL
shopt -s lastpipe
CERT_DATE=`curl ${EXPIRE_URL} -vk 2>&1 | grep -w "expire date:" | cut -c 17-40`
CERT_DATE_ISO=`date -d "${CERT_DATE}" "+%F %H%M%S"`
CHECK_DATE_ISO=`date -d "${CERT_DATE}" "+%FT%H:%M:%S"`

# Make date pretty
CERT_DATE=`date -d "${CERT_DATE}" "+%d-%b-%Y"`

# Maybe show verbose output
if [ "${VERBOSE}" == true ]; then
  echo "Certificate for ${EXPIRE_URL} expires on ${CERT_DATE}"
fi

#This is when certificate expires, minus our window
EXPIRE_CHECK=`date -d "${CHECK_DATE_ISO}Z - ${EXPIRE_DAYS} days" "+%F %H%M%S"`
#This is now
NOW_DATE=`date "+%F %H%M%S"`
#Now is greater than when the certificate expires, minus our window
if [ "${NOW_DATE}" \> "${EXPIRE_CHECK}" ]; then
  if [ "${DRY_RUN}" == true ]; then
    if [ "${VERBOSE}" == true ]; then
      echo "Certificate will expire within ${EXPIRE_DAYS} days (not sending e-mail)"
    fi
  else
    if [ "${VERBOSE}" == true ]; then
      echo "Will expire within ${EXPIRE_DAYS} days, Sending e-mail to ${EXPIRE_EMAIL}"
    fi
    #You may need to change "mail -s" to whatever works for you
    #You should also probably change the -r parameter :)
    echo -e "\n\nCertificate for ${EXPIRE_URL} expires within ${EXPIRE_DAYS} day(s) (on ${CERT_DATE})\n" | mail -r checkSSLexpired -s "Certificate for ${EXPIRE_URL} expires within ${EXPIRE_DAYS} day(s)" ${EXPIRE_EMAIL}
  fi
  exit 1
else
  if [ "${VERBOSE}" == true ]; then
    echo "Certificate will NOT expire within ${EXPIRE_DAYS} days"
  fi
  exit 0
fi

 

Leave a Comment

Notify me of followup comments via e-mail. You can also subscribe without commenting.

This site uses Akismet to reduce spam. Learn how your comment data is processed.