Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / ssl / ssl-certificate-expiry @ 0b4725d6

Historique | Voir | Annoter | Télécharger (4,9 ko)

1
#!/bin/sh -u
2
# -*- sh -*-
3
# shellcheck disable=SC2039
4

    
5
: << =cut
6

    
7
=head1 NAME
8

    
9
ssl-certificate-expiry - Plugin to monitor Certificate expiration on multiple services and ports
10

    
11
=head1 CONFIGURATION
12

    
13
  [ssl-certificate-expiry]
14
    env.services www.service.tld blah.example.net_PORT foo.example.net_PORT_STARTTLS
15

    
16
PORT is the TCP port number
17
STARTTLS is passed to openssl as "-starttls" argument. Useful for services like SMTP or IMAP implementing StartTLS.
18
  Current known values are ftp, imap, pop3 and smtp
19
  PORT is mandatory if STARTTLS is used.
20

    
21
To set warning and critical levels do like this:
22

    
23
  [ssl-certificate-expiry]
24
    env.services ...
25
    env.warning 30:
26

    
27
Alternatively, if you want to monitor hosts separately, you can create multiple symlinks named as follows.
28

    
29
  ssl-certificate-expiry_HOST_PORT
30

    
31
For example:
32

    
33
  ssl-certificate-expiry_www.example.net
34
  ssl-certificate-expiry_www.example.org_443
35
  ssl-certificate-expiry_192.0.2.42_636
36
  ssl-certificate-expiry_2001:0DB8::badc:0fee_485
37
  ssl-certificate-expiry_mail.example.net_25_smtp
38

    
39
=head2 Cron setup
40

    
41
To avoid having to run the SSL checks during the munin-update, it is possible
42
to run it from cron, and save a cachefile to be read during the update, This is
43
particularly useful when checking a large number of certificates, or when some
44
of the hosts are slow.
45

    
46
To do so, add a cron job running the plugin with cron as the argument:
47

    
48
  <minute> * * * <user> /usr/sbin/munin-run/ssl-certificate-expiry cron
49

    
50
<user> should be the user that has write permission to the MUNIN_PLUGSTATE.
51
<minute> should be a number between 0 and 59 when the check should run every hour.
52

    
53
If, for any reason, the cron script stops running, the script will revert to
54
uncached updates after the cache file is older than an hour.
55

    
56
=head1 AUTHORS
57

    
58
 * Pactrick Domack (ssl_)
59
 * Olivier Mehani (ssl-certificate-expiry)
60

    
61
 * Copyright (C) 2013 Patrick Domack <patrickdk@patrickdk.com>
62
 * Copyright (C) 2017, 2019 Olivier Mehani <shtrom+munin@ssji.net>
63

    
64
=head1 LICENSE
65

    
66
=cut
67

    
68
# shellcheck disable=SC1090
69
. "${MUNIN_LIBDIR}/plugins/plugin.sh"
70

    
71
if [ "${MUNIN_DEBUG:-0}" = 1 ]; then
72
    set -x
73
fi
74

    
75
HOSTPORT=${0##*ssl-certificate-expiry_}
76
CACHEFILE="${MUNIN_PLUGSTATE}/$(basename "${0}").cache"
77

    
78
if [ "${HOSTPORT}" != "${0}" ] \
79
	&& [ -n "${HOSTPORT}" ]; then
80
	services="${HOSTPORT}"
81
fi
82

    
83

    
84
# Read data including a certificate from stdin and output the (fractional) number of days left
85
# until the expiry of this certificate. The output is empty if parsing failed.
86
parse_valid_days_from_certificate() {
87
    local input_data
88
    local valid_until_string
89
    local valid_until_epoch
90
    local now_epoch
91
    local input_data
92
    input_data=$(cat)
93
    if echo "$input_data" | grep -q -- "-----BEGIN CERTIFICATE-----"; then
94
        valid_until_string=$(echo "$input_data" | openssl x509 -noout -enddate \
95
            | grep "^notAfter=" | cut -f 2 -d "=")
96
        if [ -n "$valid_until_string" ]; then
97
            valid_until_epoch=$(date --date="$valid_until_string" +%s)
98
            if [ -n "$valid_until_epoch" ]; then
99
                now_epoch=$(date +%s)
100
                # calculate the number of days left
101
                echo "$valid_until_epoch" "$now_epoch" | awk '{ print(($1 - $2) / (24 * 3600)); }'
102
            fi
103
        fi
104
    fi
105
}
106

    
107

    
108
print_expire_days() {
109
    local host="$1"
110
    local port="$2"
111
    local starttls="$3"
112

    
113
    # Wrap IPv6 addresses in square brackets
114
    echo "$host" | grep -q ':' && host="[$host]"
115

    
116
    local s_client_args=
117
    [ -n "$starttls" ] && s_client_args="-starttls $starttls"
118

    
119
    # shellcheck disable=SC2086
120
    echo "" | openssl s_client -CApath /etc/ssl/certs \
121
            -servername "$host" -connect "${host}:${port}" \
122
            $s_client_args 2>/dev/null \
123
        | parse_valid_days_from_certificate
124
}
125

    
126
main() {
127
    for service in $services; do
128
	if echo "$service" | grep -q "_"; then
129
	    host=$(echo "$service" | cut -f 1 -d "_")
130
	    port=$(echo "$service" | cut -f 2 -d "_")
131
	    starttls=$(echo "$service" | cut -f 3 -d "_")
132
	else
133
	    host=$service
134
	    port=443
135
	    starttls=""
136
	fi
137
	fieldname="$(clean_fieldname "$service")"
138
	valid_days=$(print_expire_days "$host" "$port" "$starttls")
139
	[ -z "$valid_days" ] && valid_days="U"
140
	printf "%s.value %s\\n" "$fieldname" "$valid_days"
141
        echo "${fieldname}.extinfo Last checked: $(date)"
142
    done
143
}
144

    
145
case ${1:-} in
146
    config)
147
	echo "graph_title SSL Certificates Expiration"
148
	echo 'graph_args --base 1000'
149
	echo 'graph_vlabel days left'
150
	echo 'graph_category security'
151
	echo "graph_info This graph shows the numbers of days before certificate expiry"
152
	for service in $services; do
153
	    fieldname=$(clean_fieldname "$service")
154
	    echo "${fieldname}.label $(echo "${service}" | sed 's/_/:/')"
155
	    print_thresholds "${fieldname}" warning critical
156
	done
157

    
158
	exit 0
159
	;;
160
    cron)
161
	UPDATE="$(main)"
162
	echo "${UPDATE}" > "${CACHEFILE}"
163
	chmod 0644 "${CACHEFILE}"
164

    
165
	exit 0
166
	;;
167
esac
168

    
169
if [ -n "$(find "${CACHEFILE}" -mmin -60 2>/dev/null)" ]; then
170
	cat "${CACHEFILE}"
171
	exit 0
172
fi
173

    
174
main