Skip to content

Instantly share code, notes, and snippets.

@dlundgren
Last active August 16, 2022 16:30
Show Gist options
  • Save dlundgren/dcdc7a93fb37c9738c6df1e6e1f97771 to your computer and use it in GitHub Desktop.
Save dlundgren/dcdc7a93fb37c9738c6df1e6e1f97771 to your computer and use it in GitHub Desktop.
Zabbix check for CRLs
#!/bin/sh
#
# script: sslcrl.check
# version: 1.0
# author: David Lundgren <dlundgren@syberisle.net>
# description: Checks the given CRL for data
# license: MIT
#
# DETAIL:
# This script uses curl to get the CRL located at the URL, and then openssl to check the CRL attributes.
#
# Intended for use with Zabbix
#
# REQUIRES:
# - bash
# - curl
# - openssl
# - coreutils
#
# USAGE:
# * Shell: ARG1 ARG2
# > # sslcrl.check URL CHECK_TYPE
#
# ARG1: URL
# URL is the url to the CRL
#
# ARG2: CHECK_TYPE
# CHECK_TYPE specifies what attribute should be check and what to return.
#
#
# CHECK_TYPES:
# * CRL Attribute Checks
# * CHECK_TYPE: count
# Return type: int
# Desc: Returns the number revoked certs
#
# * CHECK_TYPE: issuer
# Return type: text
# Desc: Returns the Issuer Name of the CRL.
#
# * CHECK_TYPE: hash
# Return type: text
# Desc: Returns the hash of the CRL
#
# * CHECK_TYPE: lastupdate
# Return type: text
# Desc: Returns CRL last updated date, example: Jun 20 10:11:12 2022 GMT
#
# * CHECK_TYPE: lifetime
# Return type: int
# Desc: Returns CRL lifetime in seconds from NOW
#
# * CHECK_TYPE: nextupdate
# Return type: text
# Desc: Returns CRL next updated date, example: Jun 20 10:11:12 2022 GMT
#
# EXAMPLES:
# Query the lifetime of the CRL at {URL}, lifetime is returned in Seconds from current date.
# Item Key: sslcrl.check[{URL},lifetime]
# Type of Information: Numeric (unsigned)
# Data Type: Decimal
# Use from shell: sslcrl.check https://ca.example.com/ecc-root.crl lifetime
#
# ADDITIONAL PARAMETERS:
# Path to OpenSSL, echo and timeout(coreutils) binaries should be set, if they differ.
# TIMEOUT specifies the connect timeout of openssl.
#
# there need to be exactly 2 arguments, if not, exit 1 (error for console)
if [ $# -ne 2 ]; then
exit 1
fi
LOC="en_US.UTF8"
export LC_ALL=$LOC
CRL_URL=$1
CHECK_TYPE=$2
CRL_FILE_NAME=$(echo "${CRL_URL}" | sed -r 's/[~\^]+//g' | sed -r 's/[^a-zA-Z0-9]+/-/g' | sed -r 's/^-+\|-+$//g' | tr '[:upper:]' '[:lower:]')
CRL_FILE="/tmp/${CRL_FILE_NAME}"
CUR_DATE=$(date +%s)
OPENSSL=${OPENSSL:=/usr/bin/openssl}
CURL=${CURL:=/usr/bin/curl}
OS_NAME=$(uname -s)
get_crl () {
# most checks happen within the same time frame so we cache the crl for 5 minutes
CRL_MTIME=0
if [ -f "${CRL_FILE}" ]; then
# Linux is an odd ball in the stat game, unlike FreeBSD/OSX
case ${OS_NAME} in
FreeBSD|Darwin)
CRL_MTIME=$(stat -r "${CRL_FILE}" | awk '{print $10}')
;;
*)
CRL_MTIME=$(stat -c '%Y' "${CRL_FILE}")
;;
esac
fi
if [ $(( CUR_DATE - CRL_MTIME )) -gt 300 ]; then
${CURL} -s "${CRL_URL}" -o "${CRL_FILE}"
fi
# test for normal
if ! ${OPENSSL} crl -in "${CRL_FILE}" -noout "$1" 2>/dev/null; then
${OPENSSL} crl -inform DER -in "${CRL_FILE}" -noout "$1" 2>/dev/null
fi
}
os_date () {
case ${OS_NAME} in
FreeBSD|Darwin)
date -j -f "%b %e %T %Y %Z" "${RESULT#nextUpdate=}" "+%s" 2>/dev/null
;;
*)
date --date="${RESULT#nextUpdate=}" "+%s" 2>/dev/null
;;
esac
}
case ${CHECK_TYPE} in
debug)
get_crl "-text"
;;
count)
RETURN=$(get_crl "-text" | grep -c 'Revocation Date:')
;;
hash)
RESULT=$(get_crl "-hash")
RETURN="${RESULT#hash=}"
;;
issuer)
RESULT=$(get_crl "-issuer")
RETURN="${RESULT#issuer=}"
;;
lastupdate)
RESULT=$(get_crl "-lastupdate")
RETURN="${RESULT#lastUpdate=}"
;;
lifetime)
RESULT=$(get_crl "-nextupdate")
EXP_DATE=$(os_date "${RESULT#nextUpdate=}")
RETURN=$(( EXP_DATE - CUR_DATE ))
;;
nextupdate)
RESULT=$(get_crl "-nextupdate")
RETURN="${RESULT#nextUpdate=}"
;;
*)
# unsupported CHECK_TYPE
exit 1
;;
esac
if [ -z "$RETURN" ]; then
echo ""
exit 1
else
echo "${RETURN}"
exit 0
fi
<?xml version="1.0" encoding="UTF-8"?>
<zabbix_export>
<version>5.0</version>
<date>2022-06-18T16:23:18Z</date>
<groups>
<group>
<name>Templates</name>
</group>
</groups>
<templates>
<template>
<template>Template CA CRL</template>
<name>Template CA CRL</name>
<groups>
<group>
<name>Templates</name>
</group>
</groups>
<applications>
<application>
<name>Certificate Authority</name>
</application>
</applications>
<items>
<item>
<name>SSL CRL time until expire</name>
<type>EXTERNAL</type>
<key>sslcrl.check[{$URL},lifetime]</key>
<delay>1h</delay>
<trends>0</trends>
<applications>
<application>
<name>Certificate Authority</name>
</application>
</applications>
<triggers>
<trigger>
<expression>{last()}&lt;=3600</expression>
<name>CA CRL expired</name>
<priority>DISASTER</priority>
</trigger>
<trigger>
<expression>{last()}&lt;604800</expression>
<name>CA CRL expires in less than 7 days</name>
<priority>HIGH</priority>
<dependencies>
<dependency>
<name>CA CRL expired</name>
<expression>{Template CA CRL:sslcrl.check[{$URL},lifetime].last()}&lt;=3600</expression>
</dependency>
</dependencies>
</trigger>
<trigger>
<expression>{last()}&lt;3888000</expression>
<name>CA CRL expires in less than 45 days</name>
<priority>AVERAGE</priority>
<dependencies>
<dependency>
<name>CA CRL expires in less than 7 days</name>
<expression>{Template CA CRL:sslcrl.check[{$URL},lifetime].last()}&lt;604800</expression>
</dependency>
</dependencies>
</trigger>
<trigger>
<expression>{last()}&lt;7776000</expression>
<name>CA CRL expires in less than 90 days</name>
<priority>WARNING</priority>
<dependencies>
<dependency>
<name>CA CRL expires in less than 45 days</name>
<expression>{Template CA CRL:sslcrl.check[{$URL},lifetime].last()}&lt;3888000</expression>
</dependency>
</dependencies>
</trigger>
</triggers>
</item>
</items>
<macros>
<macro>
<macro>{$URL}</macro>
<value>http://ca.example.com/root.crl</value>
</macro>
</macros>
</template>
</templates>
</zabbix_export>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment