@cryptotaxi247 / netdata-1 / commits / 97699c5c6

sslcheck module: (remote) SSL certificate expiry time check (#5365)

* added WIP ssl certificate expiry time check plugin * fixing bugs * more bugfixes * cleaned up * fixed graphing * More pretty readme * cleaned up style * change author * simplify * add days_until_expiration_warn and correctly calc seconds * update config * config update * readme update * return false from check if module failed to collect data * set default update_every to 60 * add alarm * add sslcheck to makefile * fix indentation * add crit to alarm * update conf * update readme * add days_until_expiration_critical * change default days_until_expiration_warning to 14 * minor

Peter Thurner committed Mar 13, 2019 at 10:14 UTC 97699c5c60342be372d776da4829167adfdfc133
7 files changed +233
collectors/python.d.plugin/Makefile.am
+1
@@ -96,6 +96,7 @@ include smartd_log/Makefile.inc
96 include spigotmc/Makefile.inc
97 include springboot/Makefile.inc
98 include squid/Makefile.inc
99 +include sslcheck/Makefile.inc
100 include tomcat/Makefile.inc
101 include tor/Makefile.inc
102 include traefik/Makefile.inc
collectors/python.d.plugin/sslcheck/Makefile.inc new
+12
@@ -0,0 +1,12 @@
1 +# SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +# THIS IS NOT A COMPLETE Makefile
4 +# IT IS INCLUDED BY ITS PARENT'S Makefile.am
5 +# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
6 +
7 +# install these files
8 +dist_python_DATA += sslcheck/sslcheck.chart.py
9 +dist_pythonconfig_DATA += sslcheck/sslcheck.conf
10 +
11 +# do not install these files, but include them in the distribution
12 +dist_noinst_DATA += sslcheck/README.md sslcheck/Makefile.inc
\ No newline at end of file
collectors/python.d.plugin/sslcheck/README.md new
+21
@@ -0,0 +1,21 @@
1 +# SSL certificate expiry check
2 +
3 +Checks the time until a remote SSL certificate expires.
4 +
5 +## Requirements
6 +
7 +None
8 +
9 +### configuration
10 +
11 +```yaml
12 +update_every : 60
13 +
14 +example_org:
15 + host: 'example.org'
16 +
17 +my_site_org:
18 + host: 'my-site.org'
19 + days_until_expiration_warning: 10
20 + days_until_expiration_critical: 1
21 +```
collectors/python.d.plugin/sslcheck/sslcheck.chart.py new
+112
@@ -0,0 +1,112 @@
1 +# -*- coding: utf-8 -*-
2 +# Description: simple ssl expiration check netdata python.d module
3 +# Original Author: Peter Thurner (github.com/p-thurner)
4 +# SPDX-License-Identifier: GPL-3.0-or-later
5 +
6 +import datetime
7 +import socket
8 +import ssl
9 +
10 +from bases.FrameworkServices.SimpleService import SimpleService
11 +
12 +
13 +update_every = 60
14 +
15 +
16 +ORDER = [
17 + 'time_until_expiration',
18 +]
19 +
20 +CHARTS = {
21 + 'time_until_expiration': {
22 + 'options': [
23 + None,
24 + 'Time Until Certificate Expiration',
25 + 'seconds',
26 + 'certificate expiration time',
27 + 'sslcheck.time_until_expiration',
28 + 'line',
29 + ],
30 + 'lines': [
31 + ['time'],
32 + ],
33 + 'variables': [
34 + ['days_until_expiration_warning'],
35 + ['days_until_expiration_critical'],
36 + ],
37 + },
38 +}
39 +
40 +
41 +SSL_DATE_FMT = r'%b %d %H:%M:%S %Y %Z'
42 +
43 +DEFAULT_PORT = 443
44 +DEFAULT_CONN_TIMEOUT = 3
45 +DEFAULT_DAYS_UNTIL_WARN_LIMIT = 14
46 +DEFAULT_DAYS_UNTIL_CRIT_LIMIT = 7
47 +
48 +
49 +class Service(SimpleService):
50 + def __init__(self, configuration=None, name=None):
51 + SimpleService.__init__(self, configuration=configuration, name=name)
52 + self.order = ORDER
53 + self.definitions = CHARTS
54 + self.host = configuration.get('host')
55 + self.port = configuration.get('port', DEFAULT_PORT)
56 + self.timeout = configuration.get('timeout', DEFAULT_CONN_TIMEOUT)
57 + self.days_warn = configuration.get('days_until_expiration_warning', DEFAULT_DAYS_UNTIL_WARN_LIMIT)
58 + self.days_crit = configuration.get('days_until_expiration_critical', DEFAULT_DAYS_UNTIL_CRIT_LIMIT)
59 +
60 + def check(self):
61 + if not self.host:
62 + self.error('host parameter is mandatory, but it is not set')
63 + return False
64 +
65 + self.debug('run check : host {host}:{port}, update every {update}s, timeout {timeout}s'.format(
66 + host=self.host, port=self.port, update=self.update_every, timeout=self.timeout))
67 +
68 + return bool(self.get_data())
69 +
70 + def get_data(self):
71 + conn = create_ssl_conn(self.host, self.timeout)
72 +
73 + try:
74 + conn.connect((self.host, self.port))
75 + except Exception as error:
76 + self.error("error on connection to {0}:{1} : {2}".format(self.host, self.port, error))
77 + return None
78 +
79 + peer_cert = conn.getpeercert()
80 + conn.close()
81 +
82 + if peer_cert is None:
83 + self.warning("no certificate was provided by {0}:{1}".format(self.host, self.port))
84 + return None
85 + elif not peer_cert:
86 + self.warning("certificate was provided by {0}:{1}, but not validated".format(self.host, self.port))
87 + return None
88 +
89 + return {
90 + 'time': cert_expiration_seconds(peer_cert),
91 + 'days_until_expiration_warning': self.days_warn,
92 + 'days_until_expiration_critical': self.days_crit,
93 + }
94 +
95 +
96 +def create_ssl_conn(hostname, timeout):
97 + context = ssl.create_default_context()
98 + conn = context.wrap_socket(
99 + socket.socket(socket.AF_INET),
100 + server_hostname=hostname,
101 + )
102 + conn.settimeout(timeout)
103 +
104 + return conn
105 +
106 +
107 +def cert_expiration_seconds(cert):
108 + expiration_date = datetime.datetime.strptime(cert['notAfter'], SSL_DATE_FMT)
109 + current_date = datetime.datetime.utcnow()
110 + delta = expiration_date - current_date
111 +
112 + return ((delta.days * 86400 + delta.seconds) * 10 ** 6 + delta.microseconds) / 10 ** 6
collectors/python.d.plugin/sslcheck/sslcheck.conf new
+76
@@ -0,0 +1,76 @@
1 +# netdata python.d.plugin configuration for sslcheck
2 +#
3 +# This file is in YaML format. Generally the format is:
4 +#
5 +# name: value
6 +#
7 +# There are 2 sections:
8 +# - global variables
9 +# - one or more JOBS
10 +#
11 +# JOBS allow you to collect values from multiple sources.
12 +# Each source will have its own set of charts.
13 +#
14 +# JOB parameters have to be indented (using spaces only, example below).
15 +
16 +# ----------------------------------------------------------------------
17 +# Global Variables
18 +# These variables set the defaults for all JOBs, however each JOB
19 +# may define its own, overriding the defaults.
20 +
21 +# update_every sets the default data collection frequency.
22 +# If unset, the python.d.plugin default is used.
23 +# update_every: 1
24 +
25 +# priority controls the order of charts at the netdata dashboard.
26 +# Lower numbers move the charts towards the top of the page.
27 +# If unset, the default for python.d.plugin is used.
28 +# priority: 60000
29 +
30 +# penalty indicates whether to apply penalty to update_every in case of failures.
31 +# Penalty will increase every 5 failed updates in a row. Maximum penalty is 10 minutes.
32 +# penalty: yes
33 +
34 +# autodetection_retry sets the job re-check interval in seconds.
35 +# The job is not deleted if check fails.
36 +# Attempts to start the job are made once every autodetection_retry.
37 +# This feature is disabled by default.
38 +# autodetection_retry: 0
39 +
40 +# ----------------------------------------------------------------------
41 +# JOBS (data collection sources)
42 +#
43 +# The default JOBS share the same *name*. JOBS with the same name
44 +# are mutually exclusive. Only one of them will be allowed running at
45 +# any time. This allows autodetection to try several alternatives and
46 +# pick the one that works.
47 +#
48 +# Any number of jobs is supported.
49 +#
50 +# All python.d.plugin JOBS (for all its modules) support a set of
51 +# predefined parameters. These are:
52 +#
53 +# job_name:
54 +# name: myname # the JOB's name as it will appear at the
55 +# # dashboard (by default is the job_name)
56 +# # JOBs sharing a name are mutually exclusive
57 +# update_every: 1 # the JOB's data collection frequency
58 +# priority: 60000 # the JOB's order on the dashboard
59 +# penalty: yes # the JOB's penalty
60 +# autodetection_retry: 0 # the JOB's re-check interval in seconds
61 +#
62 +# Additionally to the above, sslcheck also supports the following:
63 +#
64 +# host: 'host' # [required] the remote host address in either IPv4, IPv6 or as DNS name
65 +# port: 443 # [optional] the port number to check. Specify an integer, not service name. Default is 443.
66 +# timeout: 3 # [optional] the socket timeout when connecting
67 +# days_until_expiration_warning: 14 # [optional] days before the alarm status is warning. Default is 14.
68 +# days_until_expiration_critical: 7 # [optional] days before the alarm status is critical. Default is 7.
69 +#
70 +# ----------------------------------------------------------------------
71 +# AUTO-DETECTION JOBS
72 +# only one of them will run (they have the same name)
73 +
74 +# example_org:
75 +# host : 'example.org'
76 +# days_until_expiration_warning: 10
health/Makefile.am
+1
@@ -68,6 +68,7 @@ dist_healthconfig_DATA = \
68 health.d/retroshare.conf \
69 health.d/softnet.conf \
70 health.d/squid.conf \
71 + health.d/sslcheck.conf \
72 health.d/stiebeleltron.conf \
73 health.d/swap.conf \
74 health.d/tcp_conn.conf \
health/health.d/sslcheck.conf new
+10
@@ -0,0 +1,10 @@
1 +
2 +template: sslcheck_days_until_expiration
3 + on: sslcheck.time_until_expiration
4 + calc: $time
5 + units: seconds
6 + every: 60s
7 + warn: $this < $days_until_expiration_warning*24*60*60
8 + crit: $this < $days_until_expiration_critical*24*60*60
9 + info: certificate time until expiration
10 + to: webmaster