#!/bin/bash function echoerr { echo "$@" 1>&2; } function checkEnvironment { ### Check the environment ### if ! which gpg 2>&1 >/dev/null; then echoerr "Missing gpg binary" exit 3 fi # Command to download a file DOWNLOAD="" if which curl 2>&1 >/dev/null; then DOWNLOAD="curl -s -o " elif which wget 2>&1 >/dev/null; then DOWNLOAD="wget -o /dev/null -O " else echoerr "Missing curl or wget binary" exit 3 fi # Command to get information about all subkeys GPG_SHOW="gpg --with-colon --fixed-list-mode --show-keys" } function parseArguments { ### Parse arguments ### # We require a URL # and have default values for expiration durations URL="" DEBUG=false WARN=7 # days CRIT=2 # days while [[ $# -gt 0 ]]; do case $1 in -u|--url) URL="$2"; shift;; -w|--warn) WARN=$2; shift;; -c|--crit) CRIT=$2; shift;; -d|--debug) DEBUG=true;; -?|--help) echo "Check gpg expiration date. Arguments:" echo "--url URL: Where to find the GPG key" echo "--warn DAYS: Warning threshold (integer in days)" echo "--crit DAYS: Critical threshold (integer in days)" exit 0 ;; *) echoerr "Unknown argument: $1" exit 3 ;; esac shift done if [ -z "$URL" ]; then echoerr "Missing url argument (--url)" exit 3 fi WARN_s=$(($WARN*24*60*60)) CRIT_s=$(($CRIT*24*60*60)) NOW=$(date '+%s') } function log { if $DEBUG; then echo " > $@" fi } function logLine { if $DEBUG; then echo " : $@" fi } RESULT=0 # 0:OK 1:WARN 2:CRIT RESULT_INFO="" # Additional information function clearResultInfoIfResultLessThan { # if we increase the result level/severity, # we want to clear RESULT_INFO to only show the most important information if [ $RESULT -lt $1 ]; then RESULT_INFO="" fi } function expired { # This function is called if a key expired # we set RESULT to CRITICAL and prepend our information message local key=$1 local expirationDate=$2 local msg log "$key expired at $expirationDate -> RESULT=2" clearResultInfoIfResultLessThan 2 RESULT=2 msg="${RESULT_INFO}Key $key expired at $(date '+%Y-%m-%dT%H:%M:%S' --date @$expirationDate)" if [ -n "$RESULT_INFO" ]; then RESULT_INFO="$msg. $RESULT_INFO" else RESULT_INFO=$msg fi } function expire_crit { # This function is called if a key is going to expire soon (critical) # we set RESULT to CRITICAL and append our information message local key=$1 local expirationDate=$2 log "$key expires at $expirationDate (critical) -> RESULT=2" clearResultInfoIfResultLessThan 2 RESULT=2 if [ -n "$RESULT_INFO" ]; then RESULT_INFO="$RESULT_INFO. " fi RESULT_INFO="${RESULT_INFO}Key $key will expire at $(date '+%Y-%m-%dT%H:%M:%S' --date @$expirationDate)" } function expire_warn { # This function is called if a key is going to expire soon (warning) local key=$1 local expirationDate=$2 log "$key expires at $expirationDate (critical) -> RESULT=1" clearResultInfoIfResultLessThan 1 if [ $RESULT -le 1 ]; then RESULT=1 if [ -n "$RESULT_INFO" ]; then RESULT_INFO="$RESULT_INFO. " fi RESULT_INFO="${RESULT_INFO}Key $key will expire at $(date '+%Y-%m-%dT%H:%M:%S' --date @$expirationDate)" fi } METRICS="" function metrics { # This function is called for every subkey to generate the METRICS string local key=$1 local expirationDate=$2 local remaining_s=$3 METRICS="${METRICS}'$key expiration date'=$(date '+%Y-%m-%dT%H:%M:%S' --date @$expirationDate) " METRICS="${METRICS}'$key remaining'=${remaining_s}s;${WARN_s}s;${CRIT_s}s " } function parseLine { # Parse a line of GPG's output # https://www.gnupg.org/documentation/manuals/gnupg-devel/Unattended-GPG-key-generation.html local remaining_s local recordType validity keyLength keyAlgorithm keyID creationDate expirationDate certSN ownertrust userID signatureClass keyCapabilities issuerCertFingerprint flags tokenSN hashAlgorithm curveName complianceFlags lastUpdate origin comment #logLine "$@" IFS=: read -r recordType validity keyLength keyAlgorithm keyID creationDate expirationDate certSN ownertrust userID signatureClass keyCapabilities issuerCertFingerprint flags tokenSN hashAlgorithm curveName complianceFlags lastUpdate origin comment < <(echo "$@") log "keyID = $keyID, type = $recordType, expirationDate = $expirationDate" if [ -n "$expirationDate" ]; then remaining_s=$(($expirationDate-$NOW)) metrics $keyID $expirationDate $remaining_s if [ $remaining_s -le 0 ]; then expired $keyID $expirationDate elif [ $remaining_s -le $CRIT_s ]; then expire_crit $keyID $expirationDate elif [ $remaining_s -le $WARN_s ]; then expire_warn $keyID $expirationDate fi fi } function getAndParseKey { local line local infile # for appropriate error handling we cannot use pipes (at least I don't know how to) TMPFILE=$(mktemp) || exit 3 #trap 'rm -f "$TMPFILE"' RETURN #trap 'rm -f "$TMPFILE"' EXIT # If the URL is a local path, use it as input to GPG_SHOW if [ ! -f "$URL" ]; then log "Downloading $URL" $DOWNLOAD "$TMPFILE" "$URL" exit=$? if [ $exit -ne 0 ]; then echo "ERROR - Downloading failed with $exit" exit 3 fi infile="$TMPFILE" else log "Using local file $URL" infile="$URL" fi # Process with GPG cat "$infile" | $GPG_SHOW > "$TMPFILE" exit=$? if [ $exit -ne 0 ]; then echo "ERROR - gpg failed with $exit" exit 3 fi while read -r line; do parseLine "$line" done < "$TMPFILE" trap - EXIT } function printResult { if [ $RESULT -eq 2 ]; then echo -n "CRITICAL - $RESULT_INFO" elif [ $RESULT -eq 1 ]; then echo -n "WARNING - $RESULT_INFO" else echo -n "OK" fi echo -n " | " echo -n "$METRICS" } checkEnvironment parseArguments "$@" getAndParseKey printResult exit $RESULT