First commit
This commit is contained in:
commit
65a2d6d8bd
4 changed files with 369 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/test/tmp/
|
235
check_gpg_key_expiration.sh
Executable file
235
check_gpg_key_expiration.sh
Executable file
|
@ -0,0 +1,235 @@
|
||||||
|
#!/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
|
BIN
test/expiredkey
Normal file
BIN
test/expiredkey
Normal file
Binary file not shown.
133
test/test.sh
Normal file
133
test/test.sh
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
cd $(dirname $0)
|
||||||
|
|
||||||
|
function echoerr { echo "$@" 1>&2; }
|
||||||
|
|
||||||
|
if [ -d tmp ]; then
|
||||||
|
rm -rf tmp
|
||||||
|
fi
|
||||||
|
mkdir tmp
|
||||||
|
chmod 700 tmp
|
||||||
|
|
||||||
|
function generateKey {
|
||||||
|
local expiry=$1
|
||||||
|
|
||||||
|
cat <<EOF | gpg --gen-key --homedir tmp --batch
|
||||||
|
%pubring tmp/pubkey
|
||||||
|
%no-protection
|
||||||
|
%transient-key
|
||||||
|
Key-Type: 1
|
||||||
|
Key-Length: 1024
|
||||||
|
Name-Real: Test
|
||||||
|
Name-Email: bla@test
|
||||||
|
Subkey-Type: 1
|
||||||
|
Subkey-Length: 1024
|
||||||
|
Expire-Date: ${expiry}
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
function testNotExpired {
|
||||||
|
generateKey 8d
|
||||||
|
output=$(../check_gpg_key_expiration.sh -u tmp/pubkey -w 7 -c 2)
|
||||||
|
exit=$?
|
||||||
|
if [ $exit -ne 0 ]; then
|
||||||
|
echoerr "testNotExpired failed. Exit code mismatch"
|
||||||
|
echoerr "Expected: 0"
|
||||||
|
echoerr "Actual: $exit"
|
||||||
|
fi
|
||||||
|
if [[ "$output" != "OK | "* ]]; then
|
||||||
|
echoerr "testNotExpired failed. Output did not match!"
|
||||||
|
echoerr "Expected: OK | *"
|
||||||
|
echoerr "Actual: $output"
|
||||||
|
fi
|
||||||
|
echo && echo
|
||||||
|
}
|
||||||
|
|
||||||
|
function testExpireWarn {
|
||||||
|
generateKey 3d
|
||||||
|
output=$(../check_gpg_key_expiration.sh -u tmp/pubkey -w 7 -c 2)
|
||||||
|
exit=$?
|
||||||
|
if [ $exit -ne 1 ]; then
|
||||||
|
echoerr "testExpireWarn failed. Exit code mismatch"
|
||||||
|
echoerr "Expected: 1"
|
||||||
|
echoerr "Actual: $exit"
|
||||||
|
fi
|
||||||
|
if [[ "$output" != "WARNING - Key "*" will expire at "*" | "* ]]; then
|
||||||
|
echoerr "testExpireWarn failed. Output did not match!"
|
||||||
|
echoerr "Expected: WARNING - Key **************** will expire at *"
|
||||||
|
echoerr "Actual: $output"
|
||||||
|
fi
|
||||||
|
echo && echo
|
||||||
|
}
|
||||||
|
|
||||||
|
function testExpireCritical {
|
||||||
|
generateKey 1d
|
||||||
|
output=$(../check_gpg_key_expiration.sh -u tmp/pubkey -w 7 -c 2)
|
||||||
|
exit=$?
|
||||||
|
if [ $exit -ne 2 ]; then
|
||||||
|
echoerr "testExpireCritical failed. Exit code mismatch"
|
||||||
|
echoerr "Expected: 2"
|
||||||
|
echoerr "Actual: $exit"
|
||||||
|
fi
|
||||||
|
if [[ "$output" != "CRITICAL - Key "*" will expire at "*" | "* ]]; then
|
||||||
|
echoerr "testExpireCritical failed. Output did not match!"
|
||||||
|
echoerr "Expected: CRITICAL - Key **************** will expire at *"
|
||||||
|
echoerr "Actual: $output"
|
||||||
|
fi
|
||||||
|
echo && echo
|
||||||
|
}
|
||||||
|
|
||||||
|
function testExpired {
|
||||||
|
output=$(../check_gpg_key_expiration.sh -u expiredkey -w 7 -c 2)
|
||||||
|
exit=$?
|
||||||
|
if [ $exit -ne 2 ]; then
|
||||||
|
echoerr "testExpired failed. Exit code mismatch"
|
||||||
|
echoerr "Expected: 2"
|
||||||
|
echoerr "Actual: $exit"
|
||||||
|
fi
|
||||||
|
if [[ "$output" != "CRITICAL - Key DAD15AEAD4609B87 expired at 2022-03-07T14:32:37. Key 2A8350447459F0C6 expired at 2022-03-07T14:32:37 | 'DAD15AEAD4609B87 expiration date'=2022-03-07T14:32:37 'DAD15AEAD4609B87 remaining'="*";604800s;172800s '2A8350447459F0C6 expiration date'=2022-03-07T14:32:37 '2A8350447459F0C6 remaining'="*";604800s;172800s" ]]; then
|
||||||
|
echoerr "testExpired failed. Output did not match!"
|
||||||
|
echoerr "Expected: CRITICAL - Key DAD15AEAD4609B87 expired at 2022-03-07T14:32:37. Key 2A8350447459F0C6 expired at 2022-03-07T14:32:37 | 'DAD15AEAD4609B87 expiration date'=2022-03-07T14:32:37 'DAD15AEAD4609B87 remaining'=*;604800s;172800s '2A8350447459F0C6 expiration date'=2022-03-07T14:32:37 '2A8350447459F0C6 remaining'=*;604800s;172800s"
|
||||||
|
echoerr "Actual: $output"
|
||||||
|
fi
|
||||||
|
echo && echo
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFileDoesNotExist {
|
||||||
|
output=$(../check_gpg_key_expiration.sh -u this_file_does_not_exist_blablabla_43t0zq84whtrshq3tptsth)
|
||||||
|
exit=$?
|
||||||
|
if [ $exit -ne 3 ]; then
|
||||||
|
echoerr "testFileDoesNotExist failed. Exit code mismatch"
|
||||||
|
echoerr "Expected: 3"
|
||||||
|
echoerr "Actual: $exit"
|
||||||
|
fi
|
||||||
|
if [[ "$output" != "ERROR - Downloading failed with "* ]]; then
|
||||||
|
echoerr "testFileDoesNotExist failed. Output did not match!"
|
||||||
|
echoerr "Expected: ERROR - Downloading failed with *"
|
||||||
|
echoerr "Actual: $output"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFileIsNotAGpgKey {
|
||||||
|
output=$(../check_gpg_key_expiration.sh -u test.sh)
|
||||||
|
exit=$?
|
||||||
|
if [ $exit -ne 3 ]; then
|
||||||
|
echoerr "testFileIsNotAGpgKey failed. Exit code mismatch"
|
||||||
|
echoerr "Expected: 3"
|
||||||
|
echoerr "Actual: $exit"
|
||||||
|
fi
|
||||||
|
if [[ "$output" != "ERROR - gpg failed with "* ]]; then
|
||||||
|
echoerr "testFileIsNotAGpgKey failed. Output did not match!"
|
||||||
|
echoerr "Expected: ERROR - gpg failed with *"
|
||||||
|
echoerr "Actual: $output"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
testNotExpired
|
||||||
|
testExpireWarn
|
||||||
|
testExpireCritical
|
||||||
|
testExpired
|
||||||
|
testFileDoesNotExist
|
||||||
|
testFileIsNotAGpgKey
|
Loading…
Reference in a new issue