From f0d5df2902caddfd54c9e434075ee35a65542c5b Mon Sep 17 00:00:00 2001 From: Andreas Perhab Date: Wed, 2 Feb 2022 14:34:19 +0100 Subject: [PATCH 1/3] certificate_file_expiry: re-enable old defaults for warning and critical those were accidentially removed in 76170d27453f4b2df4e42a6445a6f2be5589213a --- plugins/ssl/certificate_file_expiry | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/ssl/certificate_file_expiry b/plugins/ssl/certificate_file_expiry index 0844092a..3485ce5f 100755 --- a/plugins/ssl/certificate_file_expiry +++ b/plugins/ssl/certificate_file_expiry @@ -72,6 +72,11 @@ if [ "$1" = "config" ] ; then echo "graph_category security" fi +# by default when certificate is only valid for 5 days or less emit a warning +warning=${warning:-5:} +# by default when certificate is only valid for 1 day or less emit a critical +critical=${critical:-1:} + now=$(date +%s) for cert in ${CERTS}; do cert_type=${cert%:*} From 4b8b0982881d9e23a8e36d53172d6a0cf42a2d63 Mon Sep 17 00:00:00 2001 From: Andreas Perhab Date: Wed, 2 Feb 2022 15:51:24 +0100 Subject: [PATCH 2/3] certificate_file_expiry: enable checking openvpn in config certificates --- plugins/ssl/certificate_file_expiry | 77 +++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/plugins/ssl/certificate_file_expiry b/plugins/ssl/certificate_file_expiry index 3485ce5f..c538cc5b 100755 --- a/plugins/ssl/certificate_file_expiry +++ b/plugins/ssl/certificate_file_expiry @@ -15,6 +15,14 @@ For openvpn ca.crt and crl.pem env.CERTS crl:/etc/openvpn/easy-rsa/keys/crl.pem x509:/etc/openvpn/easy-rsa/keys/ca.crt env.LOGARITHMIC yes +For openvpn inline and certificates, as described here +https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage#lbAV + + [certificate_file_expiry] + user root + env.CERTS openvpn_inline:/etc/openvpn/client.conf + env.LOGARITHMIC yes + For letsencrypt certificates [certificate_file_expiry] @@ -32,8 +40,11 @@ Warning and Critical levels can also be configured with env variables like this: # critical when certificate will be invalid within 1 day env.critical 1: -env.CERTS should be a space separated list of patterns prefixed by the type of certificate to check and a colon. All types of -certificates that openssl supports as standard commands and have a validity output are supported (e.g. x509, crl). +env.CERTS should be a space separated list of patterns prefixed by the type of certificate to check and a colon. All +types of certificates that openssl supports as standard commands and have a validity output are supported +(e.g. x509, crl). +A special type is openvpn_inline where the plugin gets the certificates directly from the openvpn conf file in between +the \n...\n and \n...\n lines and checks those with openssl x509. File patterns can be a single file (e.g. /etc/openvpn/easy-rsa/keys/crl.pem) or a pattern that matches multiple files (e.g. /etc/letsencrypt/live/*/cert.pem). @@ -78,22 +89,60 @@ warning=${warning:-5:} critical=${critical:-1:} now=$(date +%s) +get_validity() { + local file + local openssl_type + local validity_line + local validity_str_value + local validity_timestamp + local validity_seconds + openssl_type=$1 + file=$2 + if [ "$file" != "-" ] ; then + validity_line=$(/usr/bin/openssl "$openssl_type" -text -noout -in "$file" | grep -E '(Next Update|Not After)') + else + # when file is set to -- read from stdin + validity_line=$(/usr/bin/openssl "$openssl_type" -text -noout | grep -E '(Next Update|Not After)') + fi + validity_str_value=${validity_line#*:} + validity_timestamp=$(date --date="$validity_str_value" +%s) + validity_seconds=$((validity_timestamp - now)) + echo "$validity_seconds" | awk '{ print ($1 / 86400) }' +} +print_config_lines() { + name=$1 + label=$2 + echo "${name}.label ${label}" + print_warning "$name" + print_critical "$name" +} +get_openvpn_inline_cert() { + file=$1 + type=$2 + # print content between and lines (ca and cert) + awk 'BEGIN{content=0}/^<\/'"$type"'>$/{content=0}(content==1){ print $0 }/^<'"$type"'>$/{content=1}' < "$file" +} + for cert in ${CERTS}; do cert_type=${cert%:*} cert_pattern=${cert#*:} for cert_file in $cert_pattern; do - cert_name=$(clean_fieldname "$cert_file") - if [ "$1" = "config" ] ; then - echo "${cert_name}.label ${cert_file}" - print_warning "$cert_name" - print_critical "$cert_name" - elif [ "$1" = "" ] ; then - validity=$(/usr/bin/openssl "$cert_type" -text -noout -in "$cert_file" | grep -E '(Next Update|Not After)') - validity=${validity#*:} - validity=$(date --date="$validity" +%s) - validity=$((validity - now)) - validity=$(echo "$validity" | awk '{ print ($1 / 86400) }') - echo "${cert_name}.value $validity" + if [ "$cert_type" = "openvpn_inline" ] ; then + for type in "ca" "cert"; do + cert_name=$(clean_fieldname "$cert_file-$type") + if [ "$1" = "config" ] ; then + print_config_lines "$cert_name" "${cert_file} ${type}" + elif [ "$1" = "" ] ; then + echo "${cert_name}.value $(get_openvpn_inline_cert "$cert_file" "$type" | get_validity "x509" "-")" + fi + done + else + cert_name=$(clean_fieldname "$cert_file") + if [ "$1" = "config" ] ; then + print_config_lines "$cert_name" "${cert_file}" + elif [ "$1" = "" ] ; then + echo "${cert_name}.value $(get_validity "$cert_type" "$cert_file")" + fi fi done done From d9701b4f6a60d545e9b5a16264ac1bc781ae9fb1 Mon Sep 17 00:00:00 2001 From: Andreas Perhab Date: Fri, 18 Feb 2022 09:39:34 +0100 Subject: [PATCH 3/3] certificate_file_expiry: add option to ignore unexpanded patterns this helps use the same configs on multiple nodes where not all the patterns expand to existing files on all of them or when files are not yet existing --- plugins/ssl/certificate_file_expiry | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/ssl/certificate_file_expiry b/plugins/ssl/certificate_file_expiry index c538cc5b..3a8faa9c 100755 --- a/plugins/ssl/certificate_file_expiry +++ b/plugins/ssl/certificate_file_expiry @@ -55,6 +55,9 @@ env.LOGARITHMIC "yes" enables the logarithmic display of values which is useful long lived in respect to the warning level. e.g. a ca.crt that is valid for 10 years together with a crl.pem that is valid for only a few months combined with warning levels of 5 days. default is "yes" to disable set it to "no". +env.IGNORE_UNEXPANDED_PATTERNS "yes" ignores patterns that did not expand to any files. this is useful to define one +config that handles multiple types of certs where only one pattern is used. default is "no". + =head1 Dependencies Dependencies: openssl @@ -72,6 +75,7 @@ GPLv2 . "$MUNIN_LIBDIR/plugins/plugin.sh" LOGARITHMIC=${LOGARITHMIC:-yes} +IGNORE_UNEXPANDED_PATTERNS=${IGNORE_UNEXPANDED_PATTERNS:-no} if [ "$1" = "config" ] ; then echo "graph_title Certificate validity" @@ -127,6 +131,16 @@ for cert in ${CERTS}; do cert_type=${cert%:*} cert_pattern=${cert#*:} for cert_file in $cert_pattern; do + # note: if file contains a * (e.g. /etc/letsencrypt/live/*/cert.pem) it might be an unexpanded pattern + # to supress errors see IGNORE_UNEXPANDED_PATTERNS above + # shellcheck disable=SC2063 + if [ "$IGNORE_UNEXPANDED_PATTERNS" = "yes" ] \ + && [ "$cert_file" = "$cert_pattern" ] \ + && ! [ -e "$cert_file" ] \ + && echo "$cert_file" | grep -q "*" ; then + # skip unexpanded patterns when IGNORE_UNEXPANDED_PATTERNS is set to yes + continue + fi if [ "$cert_type" = "openvpn_inline" ] ; then for type in "ca" "cert"; do cert_name=$(clean_fieldname "$cert_file-$type")