Changeset - aa2802e42d9d
[Not reviewed]
0 7 1
Branko Majic (branko) - 7 years ago 2017-04-09 22:24:20
branko@majic.rs
MAR-99: Implemented script for checking local certificates (currently only expiration is supported). Updated common role to deploy the script, and set-up configuration directory for it. Updated roles that deploy certificates to also deploy configuration file for checking the certificate expiration dates.
8 files changed with 302 insertions and 1 deletions:
0 comments (0 inline, 0 general)
roles/common/files/check_certificate.sh
Show inline comments
 
new file 100755
 
#!/bin/bash
 
#
 
# check_certificate.sh
 
#
 
# Copyright (C) 2017, Branko Majic <branko@majic.rs>
 
#
 
# 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 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
#
 

	
 
program="check_certificate.sh"
 

	
 
function usage() {
 
    cat <<EOF
 
$program, a non-interactive utility for checking certificates
 

	
 
Usage: $program [OPTIONS] check_type...
 

	
 
$program is a non-interactive utility for checking certificates. Utility
 
supports a number of different checks which are passed in as positional
 
arguments. The following checks are currently implemented:
 

	
 
expiration
 
  Checks if certificate expires within designated time. Expiration period can be
 
  specified via options (see below).
 

	
 
List of certificate files to check can be passed through two mutually exclusive
 
mechanisms - via options or through configuration files. If certificates are
 
specified through options, configuration files are not read.
 

	
 
Configuration files are by default read from directory
 
/etc/check_certificate/. Each configuration file is expected to end with
 
".conf". All other files will be ignored. A different configuration directory
 
can be also specified via an option.
 

	
 
Configuration files themselves should contain one certificate per line. Blank
 
lines will be ignored.
 

	
 

	
 
$program accepts the following options:
 

	
 
    -e period
 
        Number of days before certificate expires after which the certificate
 
        should be considered as about to expire. Value is used in the following
 
        check types: expiration.
 

	
 
    -c certificate_file
 
        Path to certificate file for which the checks should be run. This option
 
        can be specified multiple times on the command line in order to verify
 
        multiple certificates.
 

	
 

	
 
    -d
 
        Enable debug output.
 

	
 
    -v
 
        Show script version and licensing information.
 

	
 
    -h
 
        Show usage help.
 

	
 

	
 
Please report bugs and send feature requests to <branko@majic.rs>.
 
EOF
 
}
 

	
 
function version() {
 
        cat <<EOF
 
$program
 

	
 
+-----------------------------------------------------------------------+
 
| Copyright (C) 2017, Branko Majic <branko@majic.rs>                    |
 
|                                                                       |
 
| 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 3 of the License, or     |
 
| (at your option) any later version.                                   |
 
|                                                                       |
 
| This program is distributed in the hope that it will be useful,       |
 
| but WITHOUT ANY WARRANTY; without even the implied warranty of        |
 
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
 
| GNU General Public License for more details.                          |
 
|                                                                       |
 
| You should have received a copy of the GNU General Public License     |
 
| along with this program.  If not, see <http://www.gnu.org/licenses/>. |
 
+-----------------------------------------------------------------------+
 

	
 
EOF
 
}
 

	
 
# Set-up colours for message printing if we're not piping and terminal is
 
# capable of outputting the colors.
 
_color_terminal=$(tput colors 2>&1)
 
if [[ -t 1 ]] && (( ${_color_terminal} > 0 )); then
 
    _text_bold=$(tput bold)
 
    _text_white=$(tput setaf 7)
 
    _text_blue=$(tput setaf 6)
 
    _text_green=$(tput setaf 2)
 
    _text_yellow=$(tput setaf 3)
 
    _text_red=$(tput setaf 1)
 
    _text_reset=$(tput sgr0)
 
else
 
    _text_bold=""
 
    _text_white=""
 
    _text_blue=""
 
    _text_green=""
 
    _text_yellow=""
 
    _text_red=""
 
    _text_reset=""
 
fi
 

	
 
# Set-up functions for printing coloured messages.
 
function debug() {
 
    if [[ $DEBUG != 0 ]]; then
 
	echo "${_text_bold}${_text_blue}[DEBUG]${_text_reset}" "$@"
 
    fi
 
}
 

	
 
function info() {
 
    echo "${_text_bold}${_text_white}[INFO] ${_text_reset}" "$@"
 
}
 

	
 
function success() {
 
    echo "${_text_bold}${_text_green}[OK]   ${_text_reset}" "$@"
 
}
 

	
 
function warning() {
 
    echo "${_text_bold}${_text_yellow}[WARN] ${_text_reset}" "$@"
 
}
 

	
 
function error() {
 
    echo "${_text_bold}${_text_red}[ERROR]${_text_reset}" "$@" >&2
 
}
 

	
 
#
 
# Checks expiration of passed-in certificate file.
 
#
 
# Arguments:
 
#
 
#   $1 - Path to certificate file to check
 
#
 
# Returns:
 
#
 
#   0 if check has passed, 1 if check has not passed.
 
#
 
function check_expiration() {
 
    local certificate_file="$1"
 
    local certificate_file_expiration_date
 
    local expiration_period_seconds
 

	
 
    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=//')
 
    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)."
 
	return 0
 
    else
 
	error "Expiration check ($expiration_period days) failed for $certificate_file (expires on $certificate_file_expiration_date)."
 
	return 1
 
    fi
 
}
 

	
 
# Exit codes
 
ERROR_SUCCESS=0
 
ERROR_PARAMETERS=1
 
ERROR_FAILED_CHECK=2
 

	
 
# If no arguments were given, just show usage help.
 
if [[ -z $1 ]]; then
 
    usage
 
    exit $ERROR_SUCCESS
 
fi
 

	
 
# Disable debug by default.
 
DEBUG=0
 

	
 
# Set-up default option values.
 
let expiration_period=30
 

	
 
# List of certificate files to check.
 
certificate_files=()
 
configuration_directory="/etc/check_certificate"
 

	
 
# Parse the arguments
 
while getopts "e:c:C:xdvh" opt; do
 
    case "$opt" in
 
	e) let expiration_period="$OPTARG";;
 
	c) certificate_files+=("$OPTARG");;
 
	C) configuration_directory="$OPTARG";;
 
	d) DEBUG=1;;
 
        v) version
 
           exit $ERROR_SUCCESS;;
 
        h) usage
 
           exit $ERROR_SUCCESS;;
 
        *) usage
 
           exit $ERROR_PARAMETERS;;
 
    esac
 
done
 
i=$OPTIND
 
shift $(($i-1))
 

	
 
# Verify parameters.
 
if [[ $# == 0 ]]; then
 
    error "At least one valid check type must be specified."
 
    exit $ERROR_PARAMETERS
 
fi
 
for check in "$@"; do
 
    if [[ $check != expiration ]]; then
 
	error "Unsupported check type specified: $check"
 
	exit $ERROR_PARAMETERS
 
    fi
 
done
 

	
 
# Load list of certificate files from configuration files if none were specified
 
# via options.
 
if [[ ${#certificate_files[@]} == 0 ]]; then
 
    for configuration_file in "$configuration_directory"/*.conf; do
 
	if [[ -f $configuration_file ]]; then
 
	    DONE=false
 
	    until "$DONE"; do
 
		read line || DONE=true
 
		[[ ! $line =~ ^[[:blank:]]*$ ]] && certificate_files+=("$line")
 
	    done < "$configuration_file"
 
	fi
 
    done
 
fi
 

	
 
# Log a warning if list of certificates is empty.
 
if [[ ${#certificate_files[@]} == 0 ]]; then
 
    warning "No certificate files were specified for checking."
 
fi
 

	
 
# Process the certificate files.
 
result=$ERROR_SUCCESS
 
for certificate_file in "${certificate_files[@]}"; do
 
    for check in "$@"; do
 
	if ! check_"$check" "${certificate_file}"; then
 
	    result=$ERROR_FAILED_CHECK
 
	fi
 
    done
 
done
 

	
 
if [[ $result == $ERROR_SUCCESS ]]; then
 
    success "All checks have passed for all certificates."
 
else
 
    error "There are some checks that have failed for at least one certificate file. Check output from the script."
 
fi
 

	
 
exit $result
roles/common/tasks/main.yml
Show inline comments
 
@@ -134,8 +134,20 @@
 
- name: Enable ferm service
 
  service: name=ferm state=started
 

	
 
- name: Deploy script for validating server certificates
 
  copy: src="check_certificate.sh" dest="/usr/local/bin/check_certificate.sh"
 
        owner=root group=root mode=755
 

	
 
- name: Set-up directory for holding configuration for certificate validation script
 
  file: path="/etc/check_certificate" state="directory"
 
        owner="root" group="root" mode="755"
 

	
 
- name: Deploy crontab entry for checking certificates
 
  cron: name="check_certificate" cron_file="check_certificate" hour=0 minute=0 job="/usr/local/bin/check_certificate.sh expiration"
 
        state=present user=nobody
 

	
 
- name: Explicitly run all handlers
 
  include: ../handlers/main.yml
 
  when: "handlers | default(False) | bool() == True"
 
  tags:
 
    - handlers
 
\ No newline at end of file
 
    - handlers
roles/ldap_server/tasks/main.yml
Show inline comments
 
@@ -66,6 +66,10 @@
 
  notify:
 
    - Restart slapd
 

	
 
- name: Deploy configuration file for checking certificate validity via cron
 
  copy: content="/etc/ssl/certs/{{ ansible_fqdn }}_ldap.pem" dest="/etc/check_certificate/{{ ansible_fqdn }}_ldap.conf"
 
        owner=root group=root mode=644
 

	
 
- name: Configure TLS for slapd (includes hardening)
 
  ldap_entry: dn=cn=config state=replace olcTLSCertificateFile="/etc/ssl/certs/{{ ansible_fqdn }}_ldap.pem" olcTLSCertificateKeyFile="/etc/ssl/private/{{ ansible_fqdn }}_ldap.key"
 
              olcTLSCipherSuite="{{ ldap_tls_ciphers }}"
roles/mail_server/tasks/main.yml
Show inline comments
 
@@ -50,6 +50,13 @@
 
  notify:
 
    - Restart Dovecot
 

	
 
- name: Deploy configuration files for checking certificate validity via cron
 
  copy: content="/etc/ssl/certs/{{ ansible_fqdn }}_{{ item }}.pem" dest="/etc/check_certificate/{{ ansible_fqdn }}_{{ item }}.conf"
 
        owner=root group=root mode=644
 
  with_items:
 
    - smtp
 
    - imap
 

	
 
- name: Install SWAKS
 
  apt: name="swaks" state=installed
 

	
roles/php_website/tasks/main.yml
Show inline comments
 
@@ -57,6 +57,10 @@
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy configuration file for checking certificate validity via cron
 
  copy: content="/etc/ssl/certs/{{ fqdn }}_https.pem" dest="/etc/check_certificate/{{ fqdn }}_https.conf"
 
        owner=root group=root mode=644
 

	
 
- name: Deploy nginx configuration file for website
 
  template: src="nginx_site.j2" dest="/etc/nginx/sites-available/{{ fqdn }}"
 
            owner=root group=root mode=640 validate="/usr/local/bin/nginx_verify_site.sh -n '{{ fqdn }}' %s"
roles/web_server/tasks/main.yml
Show inline comments
 
@@ -20,6 +20,10 @@
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy configuration file for checking certificate validity via cron
 
  copy: content="/etc/ssl/certs/{{ ansible_fqdn }}_https.pem" dest="/etc/check_certificate/{{ ansible_fqdn }}_https.conf"
 
        owner=root group=root mode=644
 

	
 
- name: Remove TLS protocol configuration from the main configuration file
 
  lineinfile: dest="/etc/nginx/nginx.conf" backrefs=yes regexp="^\s*ssl_protocols" state=absent
 
  notify:
roles/wsgi_website/tasks/main.yml
Show inline comments
 
@@ -117,6 +117,10 @@
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy configuration file for checking certificate validity via cron
 
  copy: content="/etc/ssl/certs/{{ fqdn }}_https.pem" dest="/etc/check_certificate/{{ fqdn }}_https.conf"
 
        owner=root group=root mode=644
 

	
 
- name: Deploy nginx configuration file for website
 
  template: src="nginx_site.j2" dest="/etc/nginx/sites-available/{{ fqdn }}"
 
            owner=root group=root mode=640 validate="/usr/local/bin/nginx_verify_site.sh -n '{{ fqdn }}' %s"
roles/xmpp_server/tasks/main.yml
Show inline comments
 
@@ -35,6 +35,10 @@
 
  notify:
 
    - Restart Prosody
 

	
 
- name: Deploy configuration file for checking certificate validity via cron
 
  copy: content="/etc/ssl/certs/{{ ansible_fqdn }}_xmpp.pem" dest="/etc/check_certificate/{{ ansible_fqdn }}_xmpp.conf"
 
        owner=root group=root mode=644
 

	
 
- name: Set-up directory for storing additional Prosody modules
 
  file: path=/usr/local/lib/prosody/modules/ state=directory mode=755 owner=root group=root
 

	
0 comments (0 inline, 0 general)