257 lines
6.9 KiB
Bash
Executable file
257 lines
6.9 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
function echoerr { echo "$@" 1>&2; }
|
|
|
|
function cleanup {
|
|
if [ -n "$TMPFILE" -a -f "$TMPFILE" ]; then
|
|
rm -f "$TMPFILE"
|
|
fi
|
|
if [ -n "$TMPFILE2" -a -f "$TMPFILE2" ]; then
|
|
rm -f "$TMPFILE2"
|
|
fi
|
|
if [ -n "$TMPDIR" -a -d "$TMPDIR" ]; then
|
|
rm -rf "$TMPDIR"
|
|
fi
|
|
}
|
|
trap 'cleanup' EXIT
|
|
|
|
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
|
|
if $DEBUG; then
|
|
DOWNLOAD="curl -o "
|
|
else
|
|
DOWNLOAD="curl -s -o "
|
|
fi
|
|
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
|
|
TMPDIR=$(mktemp -d) || exit 3
|
|
export GNUPGHOME=$TMPDIR # don't create ~/.gnupg directory
|
|
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|--file) URL="$2"; shift;;
|
|
-w|--warn|--warning) WARN=$2; shift;;
|
|
-c|--crit|--critical) CRIT=$2; shift;;
|
|
-d|--debug) DEBUG=true;;
|
|
-?|--help)
|
|
echo "Check gpg expiration date. Arguments:"
|
|
echo "--url URL: Where to find the GPG key (URL or path to file)"
|
|
echo "--warning DAYS: Warning threshold (integer in days)"
|
|
echo "--critical 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)'=0 "
|
|
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
|
|
|
|
# If the URL is a local path, use it as input to GPG_SHOW
|
|
if [ ! -f "$URL" ]; then
|
|
TMPFILE2=$(mktemp) || exit 3
|
|
log "Downloading $URL to $TMPFILE2: $DOWNLOAD \"$TMPFILE2\" \"$URL\""
|
|
$DOWNLOAD "$TMPFILE2" "$URL"
|
|
exit=$?
|
|
if [ $exit -ne 0 ]; then
|
|
echo "ERROR - Downloading failed with $exit"
|
|
exit 3
|
|
fi
|
|
infile="$TMPFILE2"
|
|
else
|
|
log "Using local file $URL"
|
|
infile="$URL"
|
|
fi
|
|
|
|
# Process with GPG
|
|
log "Processing $infile: cat \"$infile\" | $GPG_SHOW > \"$TMPFILE\""
|
|
cat "$infile" | $GPG_SHOW > "$TMPFILE" 2> /dev/null
|
|
exit=$?
|
|
if [ $exit -ne 0 ]; then
|
|
echo "ERROR - gpg failed with $exit"
|
|
exit 3
|
|
fi
|
|
|
|
while read -r line; do
|
|
parseLine "$line"
|
|
done < "$TMPFILE"
|
|
|
|
rm -f "$TMPFILE" && TMPFILE=""
|
|
if [ -n "$TMPFILE2" ]; then
|
|
rm -f "$TMPFILE2" && TMPFILE2=""
|
|
fi
|
|
}
|
|
|
|
|
|
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"
|
|
}
|
|
|
|
|
|
|
|
parseArguments "$@"
|
|
checkEnvironment
|
|
getAndParseKey
|
|
printResult
|
|
exit $RESULT
|