diff --git a/docs/releasenotes.rst b/docs/releasenotes.rst index 4ed26c652f453e39b387bbda86a777b449dd590c..b18ddab5d599759d617e59e862b8e4977ebe0efc 100644 --- a/docs/releasenotes.rst +++ b/docs/releasenotes.rst @@ -33,6 +33,11 @@ New features/improvements: * The ``pip`` requirements upgrade checks now do not output warning in case deployed ``.in`` file does not have a matching ``.txt`` file. + * Certificate expiration check is less verbose. No mails are sent + out any longer in case no certificates have been configured for + checking, nor in cases where all certificates have passed the + check. E.g. mails are sent out only in case some of the configured + certificates will expire within next 30 days. 2.0.0 diff --git a/docs/rolereference.rst b/docs/rolereference.rst index ba935e59874e3eb54243975d93fb55f8c0fde385..ccd94bd0068ea43c3f230414e1515229d1b3c357 100644 --- a/docs/rolereference.rst +++ b/docs/rolereference.rst @@ -282,7 +282,9 @@ The role implements the following: * Sets-up system for performing checks on certificates (currently only if they expire within less than 30 days). Roles that want their certificates checked should deploy a ``.conf`` to directory ``/etc/check_certificate/`` with paths - to certificate files, one per line. Certificates are checked on daily basis. + to certificate files, one per line. Certificates are checked on + daily basis, using crontab (resulting in failures being sent out to + the ``root`` user). * Deploys ``apticron`` package that performs checks for available package upgrades on daily basis. Mails are delivered to local ``root`` account, and can be redirected elsewhere via aliases. If using ``mail_forwarder`` or diff --git a/docs/usage.rst b/docs/usage.rst index 36b21af0742e62bca8d4e0e8ce0954892e8e3200..96f2b5f37f413d5c28d0b0e60ba5348ada086e28 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -594,11 +594,12 @@ one up first. This includes both the LDAP *server* and *client* configuration. .. note:: Another useful feature the roles implement is a check to see if - certificates will expire within the next 30 days. This check is performed - via cronjob at midnight, and results will end-up being delivered to the - ``root`` user on local server. Later on, once you have configured the mail - server, you should be able to set-up the necessary aliases to have the - mails delivered to non-local accounts too. + certificates will expire within the next 30 days. This check is + performed via cronjob at midnight, and failing results will + end-up being delivered to the ``root`` user on local + server. Later on, once you have configured the mail server, you + should be able to set-up the necessary aliases to have the mails + delivered to non-local accounts too. 1. Let's first install a couple of more tools on the Ansible server, since we will be using ``certtool`` for our improvised CA needs (run this as diff --git a/roles/common/files/check_certificate.sh b/roles/common/files/check_certificate.sh index 456579c766c2b2330be3ef78b200ace7e9ce23e3..dda8b4395c85867ad7227b848e97e8c49fd91f83 100755 --- a/roles/common/files/check_certificate.sh +++ b/roles/common/files/check_certificate.sh @@ -59,6 +59,8 @@ $program accepts the following options: can be specified multiple times on the command line in order to verify multiple certificates. + -q + Enable quiet mode. Output only warnings and errors. -d Enable debug output. @@ -121,17 +123,15 @@ fi # Set-up functions for printing coloured messages. function debug() { - if [[ $DEBUG != 0 ]]; then - echo "${_text_bold}${_text_blue}[DEBUG]${_text_reset}" "$@" - fi + [[ $DEBUG != 0 ]] && echo "${_text_bold}${_text_blue}[DEBUG]${_text_reset}" "$@" } function info() { - echo "${_text_bold}${_text_white}[INFO] ${_text_reset}" "$@" + [[ $QUIET == 0 ]] && echo "${_text_bold}${_text_white}[INFO] ${_text_reset}" "$@" } function success() { - echo "${_text_bold}${_text_green}[OK] ${_text_reset}" "$@" + [[ $QUIET == 0 ]] && echo "${_text_bold}${_text_green}[OK] ${_text_reset}" "$@" } function warning() { @@ -155,24 +155,65 @@ function error() { # function check_expiration() { local certificate_file="$1" - local certificate_file_expiration_date + local certificate_expiration_date certificate_expiration_date_in_seconds certificate_expires_in + local current_date_in_seconds local expiration_period_seconds + local status let expiration_period_seconds="$expiration_period"*24*60*60 debug "Running expiration check for file: $certificate_file" debug "Expiration period set to: $expiration_period" - certificate_file_expiration_date=$(openssl x509 -enddate -noout -in "$certificate_file" | sed -e 's/^notAfter=//') + certificate_expiration_date=$(openssl x509 -enddate -noout -in "$certificate_file" | sed -e 's/^notAfter=//') + certificate_expiration_date_in_seconds=$(date -d "$certificate_expiration_date" "+%s") + current_date_in_seconds=$(date "+%s") + let certificate_expires_in="$certificate_expiration_date_in_seconds-$current_date_in_seconds" + + if (( $certificate_expires_in >= 0 )); then + status="expires" + else + status="expired" + fi + if openssl x509 -noout -in "$certificate_file" -checkend "$expiration_period_seconds" > /dev/null; then - success "Expiration check ($expiration_period days) passed for $certificate_file (expires on $certificate_file_expiration_date)." + success "Certificate $certificate_file $status on $certificate_expiration_date, $(print_relative_period "$certificate_expires_in")." return 0 else - error "Expiration check ($expiration_period days) failed for $certificate_file (expires on $certificate_file_expiration_date)." + error "Certificate $certificate_file $status on $certificate_expiration_date, $(print_relative_period "$certificate_expires_in")." return 1 fi } +# +# Outputs period relative to current time in human-readable format +# with granularity in days. +# +# Arguments: +# +# $1 - Time period in seconds. Can be negative to denote past. +# +function print_relative_period() { + local seconds="$1" + local days leftover + + let days="$seconds/(60*60*24)" + + if (( $days == 1 )); then + echo "in $days day" + elif (( $days > 1 )); then + echo "in $days days" + elif (( $days == 0 && $seconds > 0 )); then + echo "in less than a day" + elif (( $days == 0 && $seconds < 0 )); then + echo "less than a day ago" + elif (( $days == -1 )); then + echo "one day ago" + elif (( $days < -1 )); then + echo "${days#-} days ago" + fi +} + # Exit codes ERROR_SUCCESS=0 ERROR_PARAMETERS=1 @@ -186,6 +227,7 @@ fi # Disable debug by default. DEBUG=0 +QUIET=0 # Set-up default option values. let expiration_period=30 @@ -195,11 +237,12 @@ certificate_files=() configuration_directory="/etc/check_certificate" # Parse the arguments -while getopts "e:c:C:xdvh" opt; do +while getopts "e:c:C:xqdvh" opt; do case "$opt" in e) let expiration_period="$OPTARG";; c) certificate_files+=("$OPTARG");; C) configuration_directory="$OPTARG";; + q) QUIET=1;; d) DEBUG=1;; v) version exit $ERROR_SUCCESS;; @@ -238,9 +281,9 @@ if [[ ${#certificate_files[@]} == 0 ]]; then done fi -# Log a warning if list of certificates is empty. +# Inform user that no certificates have been configured for checking. if [[ ${#certificate_files[@]} == 0 ]]; then - warning "No certificate files were specified for checking." + info "No certificate files were specified for checking." fi # Process the certificate files. diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml index 196fae3354e27cc859b2f32c0146ff742d3e6262..861fff5b90e5597804ea76824bb52f35789d4b1b 100644 --- a/roles/common/tasks/main.yml +++ b/roles/common/tasks/main.yml @@ -267,7 +267,7 @@ cron_file: "check_certificate" hour: 0 minute: 0 - job: "/usr/local/bin/check_certificate.sh expiration" + job: "/usr/local/bin/check_certificate.sh -q expiration" state: present user: nobody