summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile10
-rwxr-xr-xcrypt-expiry-check.in195
-rw-r--r--crypt-expiry-check.service.in6
-rw-r--r--crypt-expiry-check.timer.in11
5 files changed, 162 insertions, 63 deletions
diff --git a/.gitignore b/.gitignore
index 9ab43ca..d8403f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,6 @@ crypt-expiry-check.cron
man.commons
*.common
*.1
+crypt-expiry-check.service
+crypt-expiry-check.timer
+.idea
diff --git a/Makefile b/Makefile
index f56bac7..51585d5 100644
--- a/Makefile
+++ b/Makefile
@@ -24,10 +24,11 @@ ETCDIR = /etc
CRONDIR = /etc/cron.daily
BINDIR = /usr/bin
MANDIR = /usr/share/man
+SYSTEMDDIR = /usr/lib/systemd/system
-VERSION = 4.0.12
+VERSION = 4.4.3
-all: man.commons crypt-expiry-check crypt-expiry-check.cron crypt-expiry-check.1
+all: man.commons crypt-expiry-check crypt-expiry-check.cron crypt-expiry-check.1 crypt-expiry-check.service crypt-expiry-check.timer
%: %.in
sed "s/#VERSION#/$(VERSION)/; s@#CRONDIR#@$(CRONDIR)@; s@#BINDIR#@$(BINDIR)@; s@#ETCDIR#@$(ETCDIR)@" $< > $@
@@ -43,7 +44,8 @@ all: man.commons crypt-expiry-check crypt-expiry-check.cron crypt-expiry-check.1
.PHONY: install dist clean
install: all
- install -D -m0755 crypt-expiry-check.cron $(DESTDIR)$(CRONDIR)/crypt-expiry-check
+ [ -z "$(CRONDIR)" ] || install -D -m0755 crypt-expiry-check.cron $(DESTDIR)$(CRONDIR)/crypt-expiry-check
+ [ -z "$(SYSTEMDDIR)" ] || install -D -m0644 -t $(DESTDIR)$(SYSTEMDDIR) crypt-expiry-check.service crypt-expiry-check.timer
install -D -m0755 -t $(DESTDIR)$(BINDIR) crypt-expiry-check
install -D -m0644 -t $(DESTDIR)$(MANDIR)/man1 crypt-expiry-check.1
install -D -m0644 -t $(DESTDIR)$(ETCDIR) crypt-expiry.checks
@@ -51,7 +53,7 @@ install: all
clean:
ls -A | \
grep "^\($(shell sed 's|\.|\\.|; s|\*|.*|; s|$$|\\|' .gitignore | tr '\n' '\|')\)\$$" | \
- xargs -r rm
+ xargs -r rm -rf --one-file-system
dist: clean
git status --porcelain 2> /dev/null | grep -q "\S" && (git add .; git commit -m"neue Version: $(VERSION)") || true
diff --git a/crypt-expiry-check.in b/crypt-expiry-check.in
index 3846d7f..7ce5eae 100755
--- a/crypt-expiry-check.in
+++ b/crypt-expiry-check.in
@@ -6,13 +6,13 @@
# Author of ssl-cert-check: Matty < matty91 at gmail dot com >
# Maintainer of crypt-expiry-check: Erich < crux at eckner dot net >
#
-# Purpose:
+# Purpose:
# crypt-expiry-check checks to see if a digital certificate in X.509 format
-# or a GnuPG-key has expired. ssl-cert-check can be run in interactive
-# and batch mode, and provides facilities to alarm if a certificate is
+# or a GnuPG-key has expired. ssl-cert-check can be run in interactive
+# and batch mode, and provides facilities to alarm if a certificate is
# about to expire.
#
-# License:
+# License:
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -25,12 +25,12 @@
#
# Requirements:
# Requires openssl gnupg
-#
-# Installation:
+#
+# Installation:
# Copy the shell script to a suitable location
#
# Usage:
-# Refer to the usage() sub-routine, or invoke crypt-expiry-check
+# Refer to the usage() sub-routine, or invoke crypt-expiry-check
# with the "-h" option.
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/ssl/bin:/usr/sfw/bin
@@ -80,11 +80,12 @@ OPENSSL=$(which openssl)
PRINTF=$(which printf)
SED=$(which sed)
TEE=$(which tee)
+TR=$(which tr)
SORT=$(which sort)
TAIL=$(which tail)
MKTEMP=$(which mktemp)
GPG=$(which gpg)
-HOSTNAME=$(hostname)
+HOSTNAME=$(uname -n)
# Try to find a mail client
MAIL="cantfindit"
@@ -112,26 +113,36 @@ set_retcode()
[ ${RETCODE} -lt $1 ] && RETCODE=$1
}
+format_date()
+{
+ if echo "$*" | ${GREP} -qx '[0-9]\+'; then
+ ${DATE} '+%F' -d@"$*"
+ elif echo "$*" | ${GREP} -qx '[0-9]\+-[0-9]\+-[0-9]\+'; then
+ ${DATE} '+%F' -d"$*"
+ else
+ ${DATE} -d"$(echo "$*" | ${AWK} '{ print $1, $2, $4 }')" +%F
+ fi
+}
+
#####################################################################
# Purpose: Print a line with the expiraton interval
# Arguments:
# $1 -> Hostname
-# $2 -> TCP Port
+# $2 -> TCP Port
# $3 -> Status of certification (e.g., expired or valid)
# $4 -> Date when certificate will expire
-# $5 -> Days left until the certificate will expire
+# $5 -> Days left until the certificate will expire
# $6 -> Issuer of the certificate
#####################################################################
-prints()
+prints()
{
if ${ISSUER} && ! ${VALIDATION}
then
- MIN_DATE=$(echo $4 | ${AWK} '{ print $1, $2, $4 }')
if ${NAGIOS}
then
- ${PRINTF} "%-35s %-17s %-8s %-11s %-4s %-30s\n" "$1:$2" "$6" "$3" "${MIN_DATE}" \|days="$5"
+ ${PRINTF} "%-35s %-17s %-8s %-11s %-4s %-30s\n" "$1:$2" "$6" "$3" "$4" \|days="$5"
else
- ${PRINTF} "%-35s %-17s %-8s %-11s %-4s %-30s\n" "$1:$2" "$6" "$3" "${MIN_DATE}" "$5"
+ ${PRINTF} "%-35s %-17s %-8s %-11s %-4s %-30s\n" "$1:$2" "$6" "$3" "$4" "$5"
fi
elif ${ISSUER} && ${VALIDATION}
then
@@ -139,13 +150,12 @@ prints()
elif ! ${VALIDATION}
then
- MIN_DATE=$(echo $4 | ${AWK} '{ print $1, $2, $4 }')
if ${NAGIOS}
then
- ${PRINTF} "%-47s %-12s %-12s %-4s %-30s\n" "$1:$2" "$3" "${MIN_DATE}" \|days="$5"
+ ${PRINTF} "%-47s %-12s %-12s %-4s %-30s\n" "$1:$2" "$3" "$4" \|days="$5"
else
- ${PRINTF} "%-47s %-12s %-12s %-4s %-30s\n" "$1:$2" "$3" "${MIN_DATE}" "$5"
- fi
+ ${PRINTF} "%-47s %-12s %-12s %-4s %-30s\n" "$1:$2" "$3" "$4" "$5"
+ fi
else
${PRINTF} "%-35s %-35s %-32s\n" "$1:$2" "$7" "$8"
fi
@@ -157,10 +167,10 @@ prints()
# Arguments:
# None
####################################################
-print_heading()
+print_heading()
{
if ! ${NOHEADER}
- then
+ then
if ${ISSUER} && ! ${NAGIOS} && ! ${VALIDATION}
then
${PRINTF} "\n%-35s %-17s %-8s %-11s %-4s\n" "Host" "Issuer" "Status" "Expires" "Days" >> ${STDOUT_TMP}
@@ -170,12 +180,12 @@ print_heading()
then
${PRINTF} "\n%-35s %-35s %-32s %-17s\n" "Host" "Common Name" "Serial #" "Issuer" >> ${STDOUT_TMP}
echo "----------------------------------- ----------------------------------- -------------------------------- -----------------" >> ${STDOUT_TMP}
-
+
elif ! ${NAGIOS} && ! ${VALIDATION}
then
${PRINTF} "\n%-47s %-12s %-12s %-4s\n" "Host" "Status" "Expires" "Days" >> ${STDOUT_TMP}
echo "----------------------------------------------- ------------ ------------ ----" >> ${STDOUT_TMP}
-
+
elif ! ${NAGIOS} && ${VALIDATION}
then
${PRINTF} "\n%-35s %-35s %-32s\n" "Host" "Common Name" "Serial #" >> ${STDOUT_TMP}
@@ -191,11 +201,11 @@ print_heading()
# Arguments:
# None
##########################################
-usage()
+usage()
{
>&2 echo "$(basename "$0") checks expiration of gpg keys and X.509 certificates and sends emails if keys are about to expire."
>&2 echo ""
- >&2 echo "Usage: $0 [ -e email address ] [ -x days ] [-q] [-a] [-b] [-h] [-i] [-n] [-v] { [ -s common_name:port] } || { [ -f cert_file ] } || { [ -c certificate file ] } || { [ -g email address ] }"
+ >&2 echo "Usage: $0 [ -e email address ] [ -x days ] [-q] [-a] [-b] [-h] [-i] [-n] [-v] { [ -s common_name:port] } || { [ -f cert_file ] } || { [ -c certificate file ] } || { [ -g email address ] }"
>&2 echo ""
>&2 echo " -a Send a warning message through E-mail"
>&2 echo " -b Will not print header"
@@ -208,7 +218,9 @@ usage()
>&2 echo " -i Print the issuer of the certificate"
>&2 echo " -k password PKCS12 file password"
>&2 echo " -n Run as a Nagios plugin"
+ >&2 echo " -N directory Check nginx certificates in directory's config files."
>&2 echo " -q Don't print anything on the console"
+ >&2 echo " -r url Like -c, but download cert from url."
>&2 echo " -s commmon_name:port Server and Port to connect to (interactive mode)"
>&2 echo " -t type Specify the certificate type"
>&2 echo " -v Specify a specific protocol version to use (tls, ssl2, ssl3)"
@@ -239,7 +251,7 @@ check_server_status() {
elif [ "_${2}" = "_pop3" -o "_${2}" = "_110" ]
then
TLSFLAG="-starttls pop3"
-
+
elif [ "_${2}" = "_imap" -o "_${2}" = "_143" ]
then
TLSFLAG="-starttls imap"
@@ -282,12 +294,12 @@ check_server_status() {
then
prints ${1} ${2} "Cannot resolve domain" "Unknown" | ${TEE} -a ${MAILOUT_TMP} >> ${STDOUT_TMP}
set_retcode 3
-
+
elif ${GREP} -iq "Operation timed out" ${ERROR_TMP}
then
prints ${1} ${2} "Operation timed out" "Unknown" | ${TEE} -a ${MAILOUT_TMP} >> ${STDOUT_TMP}
set_retcode 3
-
+
elif ${GREP} -iq "ssl handshake failure" ${ERROR_TMP}
then
prints ${1} ${2} "SSL handshake failed" "Unknown" | ${TEE} -a ${MAILOUT_TMP} >> ${STDOUT_TMP}
@@ -297,7 +309,7 @@ check_server_status() {
then
prints ${1} ${2} "Connection timed out" "Unknown" | ${TEE} -a ${MAILOUT_TMP} >> ${STDOUT_TMP}
set_retcode 3
-
+
else
check_file_status ${CERT_TMP} $1 $2 $3
fi
@@ -330,6 +342,50 @@ check_remote_file_status() {
}
#####################################################
+### Check the expiration status of nginx certificates
+### Accepts one parameter:
+### $1 -> directory to nginx configurations
+#####################################################
+
+check_nginx_configuration() {
+ CONFIGDIR=${1}
+ FWARNDAYS=${2:-${WARNDAYS}}
+
+ while read -r line; do
+ {
+ read -r _ HOST _
+ read -r _ FILE
+ } < <(
+ printf '%s\n' "${line}" \
+ | "${SED}" '
+ s/[;{}]/\0\n/g
+ ' \
+ | "${SED}" -n '
+ /^\(server_name\|ssl_certificate\)\s/p
+ ' \
+ | "${SORT}" \
+ | "${SED}" '
+ s/;$//
+ '
+ )
+ check_file_status "${FILE}" 'NGINX' "${HOST// /, }" "${WARNDAYS}"
+ done < <(
+ find "${CONFIGDIR}" \
+ \( -type f -o -type l \) \
+ -exec "${SED}" '
+ s/#.*$//
+ s/^\s*//
+ s/\s*$//
+ ' {} \; \
+ | "${TR}" -d '\n' \
+ | "${SED}" '
+ s/}server\s*{/\n\0/g
+ ' \
+ | "${GREP}" -wF 'ssl_certificate'
+ )
+}
+
+#####################################################
### Check the expiration status of a certificate file
### Accepts three parameters:
### $1 -> certificate file to process
@@ -359,10 +415,11 @@ check_file_status() {
# send the informational message to /dev/null
${OPENSSL} pkcs12 -nokeys -in ${CERTFILE} \
-out ${CERT_TMP} -clcerts -password pass:${PKCSDBPASSWD} 2> /dev/null
-
+
# Extract the expiration date from the certificate
CERTDATE=$(${OPENSSL} x509 -in ${CERT_TMP} -enddate -noout | \
${SED} 's/notAfter\=//')
+ CERTDATE=$(${DATE} +%s -d "${CERTDATE}")
# Extract the issuer from the certificate
CERTISSUER=$(${OPENSSL} x509 -in ${CERT_TMP} -issuer -noout | \
@@ -373,14 +430,15 @@ check_file_status() {
COMMONNAME=$(${OPENSSL} x509 -in ${CERT_TMP} -subject -noout | \
${SED} -e 's/.*CN=//' | \
${SED} -e 's/\/.*//')
-
+
### Grab the serial number from the X.509 certificate
SERIAL=$(${OPENSSL} x509 -in ${CERT_TMP} -serial -noout | \
${SED} -e 's/serial=//')
else
# Extract the expiration date from the ceriticate
- CERTDATE=$(${OPENSSL} x509 -in ${CERTFILE} -enddate -noout -inform ${CERTTYPE} | \
- ${SED} 's/notAfter\=//')
+ CERTDATE=$(while ${OPENSSL} x509 -enddate -noout -inform ${CERTTYPE} 2>/dev/null; do :; done <${CERTFILE} | \
+ ${SED} 's/notAfter\=//' | \
+ xargs -rI __ ${DATE} +%s -d "__")
# Extract the issuer from the certificate
CERTISSUER=$(${OPENSSL} x509 -in ${CERTFILE} -issuer -noout -inform ${CERTTYPE} | \
@@ -396,7 +454,8 @@ check_file_status() {
fi
# Convert the date to seconds, and get the diff between NOW and the expiration date
- CERTDIFF=$[$(date +%s -d "${CERTDATE}") - $(date +%s)]
+ CERTDIFF=$[${CERTDATE} - $(${DATE} +%s)]
+ CERTDATE=$(format_date "${CERTDATE}")
if [ ${CERTDIFF} -lt 0 ]
then
CERTDIFF=$[$[${CERTDIFF}+1]/3600/24-1]
@@ -441,25 +500,31 @@ check_gpg_key_status() {
exit 1
fi
- KEY_INFO=$(${GPG_COMMAND} --list-secret-keys "${GPG_ADDRESS}" 2> /dev/null)
- [ -z "${KEY_INFO}" ] && KEY_INFO=$(${GPG_COMMAND} --list-keys "${GPG_ADDRESS}")
-
- KEY_DATE_STR=$(
- echo "${KEY_INFO}" | \
- ${GREP} "\[\(expire[ds]\|verfallen\|verf..\?llt\):[^]]*]" | \
- ${SED} "s#^.*\[\(expire[ds]\|verfallen\|verf..\?llt\):\s*\(\S[^]]*\)].*\$#\2#" | \
- ${SORT} | \
- ${TAIL} -n1
- )
- if [ -z "${KEY_DATE_STR}" ]
+ KEYS=$(${GPG_COMMAND} --list-secret-keys --with-colons "${GPG_ADDRESS}" 2>/dev/null)
+ [ -z "${KEYS}" ] && KEYS=$(${GPG_COMMAND} --list-keys --with-colons "${GPG_ADDRESS}" 2>/dev/null)
+
+ KEY_DATE=$(
+ echo "${KEYS}" \
+ | ${AWK} -F: '$1 == "fpr" {print $10}' \
+ | ${SORT} -u \
+ | while read -r KEY; do
+ ${GPG_COMMAND} --list-keys --with-colons "${KEY}" \
+ | awk -F: '$1 == "sub" || $1 == "pub" {print $7}' \
+ | ${SORT} -r \
+ | tail -n1
+ done \
+ | ${SORT} \
+ | tail -n1
+ )
+ if [ -z "${KEY_DATE}" ]
then
echo "No valid gpg-key found for ${GPG_ADDRESS}." | ${TEE} -a ${MAILOUT_TMP} >> ${STDOUT_TMP}
set_retcode 2
- else
- KEY_DATE=$(date +%s -ud "${KEY_DATE_STR}")
+ return
fi
- KEY_DIFF=$[${KEY_DATE} - $(date +%s)]
+ KEY_DIFF=$[${KEY_DATE} - $(${DATE} +%s)]
+ KEY_DATE=$(format_date "${KEY_DATE}")
if [ ${KEY_DIFF} -lt 0 ]
then
KEY_DIFF=$[$[${KEY_DIFF}+1]/3600/24-1]
@@ -470,24 +535,24 @@ check_gpg_key_status() {
if [ ${KEY_DIFF} -lt 0 ]
then
echo "The GPG key for ${GPG_ADDRESS} has expired!" >> ${MAILOUT_TMP}
- prints "GPG" " ${GPG_ADDRESS}" "Expired" "${KEY_DATE_STR}" "${KEY_DIFF}" "" "" "" >> ${STDOUT_TMP}
+ prints "GPG" " ${GPG_ADDRESS}" "Expired" "${KEY_DATE}" "${KEY_DIFF}" "" "" "" >> ${STDOUT_TMP}
set_retcode 2
elif [ ${KEY_DIFF} -lt ${FWARNDAYS} ]
then
- echo "The GPG key for ${GPG_ADDRESS} will expire on ${KEY_DATE_STR}" >> ${MAILOUT_TMP}
- prints "GPG" " ${GPG_ADDRESS}" "Expiring" "${KEY_DATE_STR}" "${KEY_DIFF}" "" "" "" >> ${STDOUT_TMP}
+ echo "The GPG key for ${GPG_ADDRESS} will expire on ${KEY_DATE}" >> ${MAILOUT_TMP}
+ prints "GPG" " ${GPG_ADDRESS}" "Expiring" "${KEY_DATE}" "${KEY_DIFF}" "" "" "" >> ${STDOUT_TMP}
set_retcode 1
else
- prints "GPG" " ${GPG_ADDRESS}" "Valid" "${KEY_DATE_STR}" "${KEY_DIFF}" "" "" "" >> ${STDOUT_TMP}
+ prints "GPG" " ${GPG_ADDRESS}" "Valid" "${KEY_DATE}" "${KEY_DIFF}" "" "" "" >> ${STDOUT_TMP}
fi
}
#################################
### Start of main program
#################################
-while getopts abc:e:f:g:G:hik:nqr:s:t:x:v:VZ option
+while getopts abc:e:f:g:G:hik:nN:qr:s:t:v:Vx:Z option
do
case "${option}"
in
@@ -523,6 +588,9 @@ do
n)
NAGIOS=true
;;
+ N)
+ NGINXDIRS[${#NGINXDIRS[@]}]=${OPTARG}
+ ;;
q)
QUIET=true
;;
@@ -595,10 +663,10 @@ then
fi
### Check to make sure the sed and awk binaries are available
-if [ ! -f ${SED} ] || [ ! -f ${AWK} ] || [ ! -f ${TEE} ] || [ ! -f ${SORT} ] || [ ! -f ${TAIL} ]
+if [ ! -f ${SED} ] || [ ! -f ${AWK} ] || [ ! -f ${TEE} ] || [ ! -f ${SORT} ] || [ ! -f ${TAIL} ] || [ ! -f "${TR}" ]
then
- >&2 echo "ERROR: Unable to locate the sed, awk, tee, sort or tail binary."
- >&2 echo "FIX: Please modify the \${SED}, \${AWK}, \${TEE}, \${SORT}, \${TAIL} variables in the program header."
+ >&2 echo "ERROR: Unable to locate the sed, awk, tee, sort, tail or tr binary."
+ >&2 echo "FIX: Please modify the \${SED}, \${AWK}, \${TEE}, \${SORT}, \${TAIL}, \${TR} variables in the program header."
exit 1
fi
@@ -629,7 +697,7 @@ else
exit 1
fi
-if [ $[${#HOSTS[@]} + ${#SERVERFILES[@]} + ${#CERTFILES[@]} + ${#REMOTECERTFILES[@]} + ${#CHECKADDRESSES[@]}] -eq 0 ]
+if [ $[${#HOSTS[@]} + ${#SERVERFILES[@]} + ${#CERTFILES[@]} + ${#REMOTECERTFILES[@]} + ${#CHECKADDRESSES[@]} + ${#NGINXDIRS[@]}] -eq 0 ]
then
>&2 echo "ERROR: Nothing to check."
usage
@@ -643,6 +711,12 @@ do
check_server_status "${HOSTS[${i}]}" "${PORTS[${i}]}"
done
+for (( i=0; i<${#NGINXDIRS[@]}; i++ ))
+do
+ check_nginx_configuration "${NGINXDIRS[@]}"
+# check_file_status "${HOST}" "FILE" "${HOST}" "${FWARNDAYS}"
+done
+
for (( i=0; i<${#SERVERFILES[@]}; i++ ))
do
while read FWARNDAYS PORT HOST
@@ -653,6 +727,9 @@ do
elif [ "${PORT}" = "REMOTEFILE" ]
then
check_remote_file_status "${HOST}" "REMOTEFILE" "${HOST}" "${FWARNDAYS}"
+ elif [ "${PORT}" = "NGINX" ]
+ then
+ check_nginx_configuration "${HOST}" "${FWARNDAYS}"
elif [ "${PORT}" = "GPG" ]
then
check_gpg_key_status "${GPG}" "${HOST}" "${FWARNDAYS}"
@@ -663,8 +740,8 @@ do
check_server_status "${HOST}" "${PORT}" "${FWARNDAYS}"
fi
done < <(
- sed '
- /^#|^$/d
+ "${SED}" '
+ /^#\|^$/d
s/^\([0-9]\+\) \+\(.*\S\) \+\(\S\+\)$/\1 \3 \2/
t
s/^\(.*\S\) \+\(\S\+\)$/'"${WARNDAYS}"' \2 \1/
@@ -697,7 +774,7 @@ then
(
echo "To: ${ADMIN}"
echo "From: $(whoami)@$(hostname)"
- echo "Subject: $(basename $0) at $(date)"
+ echo "Subject: $(basename $0) at $(${DATE})"
echo ""
cat ${MAILOUT_TMP}
) | ${MAIL} -t
diff --git a/crypt-expiry-check.service.in b/crypt-expiry-check.service.in
new file mode 100644
index 0000000..18e320d
--- /dev/null
+++ b/crypt-expiry-check.service.in
@@ -0,0 +1,6 @@
+[Unit]
+Description=check expiry of surveilled keys/certificates
+
+[Service]
+Environment=MAILTO=me@example.com
+ExecStart=#BINDIR#/crypt-expiry-check -qa -e $MAILTO -f #ETCDIR#/crypt-expiry.checks
diff --git a/crypt-expiry-check.timer.in b/crypt-expiry-check.timer.in
new file mode 100644
index 0000000..e153ba5
--- /dev/null
+++ b/crypt-expiry-check.timer.in
@@ -0,0 +1,11 @@
+[Unit]
+Description=check expiry of surveilled keys/certificates twice a day
+
+[Timer]
+AccuracySec=1us
+OnBootSec=15min
+OnUnitActiveSec=12h
+RandomizedDelaySec=1h
+
+[Install]
+WantedBy=timers.target