-
Notifications
You must be signed in to change notification settings - Fork 537
Active Check for remaining validity of Certificate Revocation Lists #331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f9be378
1be3a33
53c152a
c046ed3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| title: Check CRL expiry | ||
| agents: active | ||
| catalog: agentless | ||
| license: GPL | ||
| distribution: check_mk | ||
|
|
||
| item: | ||
| The URL of the given CRL | ||
|
|
||
| description: | ||
| This check screens the remaining validity of a CRL. | ||
| The Check can go into warning or critical if the remaining time | ||
| is too short. | ||
| The default tresholds are 7 days for warning and | ||
| 2 days for criticial. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
| # Copyright (C) 2019 tribe29 GmbH - License: GNU General Public License v2 | ||
| # This file is part of Checkmk (https://checkmk.com). It is subject to the terms and | ||
| # conditions defined in the file COPYING, which is part of this source code package. | ||
|
|
||
| # author: Oguzhan Cicek, OpenSource Security GmbH - oguzhan(at)os-s.de | ||
|
|
||
|
|
||
| def check_crl_arguments(params): | ||
| url = params["url"] | ||
| warn = params["time"][0] | ||
| crit = params["time"][1] | ||
| return f"-u {url} -w {warn} -c {crit}" | ||
|
|
||
|
|
||
| def check_crl_description(params): | ||
| url = params["url"] | ||
| return f"CRL: {url}" | ||
|
|
||
|
|
||
| active_check_info["crl"] = { | ||
| "command_line": "check_crl $ARG1$", | ||
| "argument_function": check_crl_arguments, | ||
| "service_description": check_crl_description, | ||
| "has_perfdata": False, | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
| # Copyright (C) 2013 - Remy van Elst | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adjust file header please
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adjust file header please |
||
|
|
||
| # 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/>. | ||
|
|
||
| # Mark Ruys <mark.ruys@peercode.nl> - 2015-8-27 | ||
| # Changelog: - catch openssl parsing errors | ||
| # - clean up temporary file on error | ||
| # - add support for PEM CRL's | ||
| # - fix message when CRL has been expired | ||
| # - pretty print duration | ||
|
|
||
| # Jeroen Nijhof <jnijhof@digidentity.eu> | ||
| # Changelog: - fixed timezone bug by comparing GMT with GMT | ||
| # - changed hours to minutes for even more precision | ||
|
|
||
| # Remy van Elst - raymii.org - 2012 | ||
| # 05.11.2012 | ||
| # Changelog: - check with hours instead of dates for more precision, | ||
| # - URL errors are now also catched as nagios exit code. | ||
|
|
||
| # Michele Baldessari - Leitner Technologies - 2011 | ||
| # 23.08.2011 | ||
|
|
||
| # Oguzhan Cicek - OpenSource Security GmbH - oguzhan(at)os-s.de - 2021 | ||
| # 05.04.2021 | ||
| # Changelog: - added argparse parsing | ||
| # - added handling for DER-Certificates | ||
|
|
||
| import time | ||
| import datetime | ||
| import getopt | ||
| import os | ||
| import pprint | ||
| import subprocess | ||
| import sys | ||
| import tempfile | ||
| import typing | ||
| import argparse | ||
| import urllib.request, urllib.parse, urllib.error | ||
|
|
||
|
|
||
| def check_crl(url: str, warn: int, crit: int) -> (int, str): | ||
| tmpcrl = tempfile.mktemp(".crl") | ||
| #request = urllib.request.urlretrieve(url, tmpcrl) | ||
| try: | ||
| urllib.request.urlretrieve(url, tmpcrl) | ||
| except: | ||
| msg = "CRL could not be retrieved: %s" % url | ||
| os.remove(tmpcrl) | ||
| return 2, msg | ||
|
|
||
| try: | ||
| inform = 'DER' | ||
| crlfile = open(tmpcrl, "r") | ||
| try: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know why and when this is necessary? Probably, this PR is related:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, we still need some clarification
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, we still need some clarification |
||
| for line in crlfile: | ||
| if "BEGIN X509 CRL" in line: | ||
| inform = 'PEM' | ||
| break | ||
| except UnicodeDecodeError: | ||
| pass | ||
| crlfile.close() | ||
|
|
||
| ret = subprocess.check_output(["/usr/bin/openssl", "crl", "-inform", inform, "-noout", "-nextupdate", "-in", tmpcrl], stderr=subprocess.STDOUT) | ||
| except: | ||
| msg = "CRL could not be parsed: %s %s" % url | ||
| os.remove(tmpcrl) | ||
| return 3, msg | ||
|
|
||
| nextupdate = ret.strip().decode('utf-8').split("=") | ||
| os.remove(tmpcrl) | ||
| eol = time.mktime(time.strptime(nextupdate[1],"%b %d %H:%M:%S %Y GMT")) | ||
| today = time.mktime(datetime.datetime.utcnow().timetuple()) | ||
| minutes = (eol - today) / 60 | ||
| if abs(minutes) < 4 * 60: | ||
| expires = minutes | ||
| unit = "minutes" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please take a look at
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please check
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please check cmk.utils.render.Age |
||
| elif abs(minutes) < 2 * 24 * 60: | ||
| expires = minutes / 60 | ||
| unit = "hours" | ||
| else: | ||
| expires = minutes / (24 * 60) | ||
| unit = "days" | ||
| gmtstr = time.asctime(time.localtime(eol)) | ||
| if minutes < 0: | ||
| msg = "CRL expired %d %s ago (on %s GMT)" % (-expires, unit, gmtstr) | ||
| exitcode = 2 | ||
| elif minutes <= crit: | ||
| msg = "CRL expires in %d %s (on %s GMT)" % (expires, unit, gmtstr) | ||
| exitcode = 2 | ||
| elif minutes <= warn: | ||
| msg = "CRL expires in %d %s (on %s GMT)" % (expires, unit, gmtstr) | ||
| exitcode = 1 | ||
| else: | ||
| msg = "CRL expires in %d %s (on %s GMT)" % (expires, unit, gmtstr) | ||
| exitcode = 0 | ||
|
|
||
| return exitcode, msg | ||
|
|
||
| def usage(): | ||
| sys.stdout.write("check_crl.py -h|--help -v|--verbose -u|--url=<url> -w|--warning=<minutes> -c|--critical=<minutes>") | ||
| sys.stdout.write("") | ||
| sys.stdout.write("Example, if you want to get a warning if a CRL expires in 8 hours and a critical if it expires in 6 hours:") | ||
| sys.stdout.write("./check_crl.py -u \"http://domain.tld/url/crl.crl\" -w 480 -c 360") | ||
|
|
||
| def main(): | ||
| parser = argparse.ArgumentParser() | ||
| parser.add_argument("--url", "-u", required=True, type=str) | ||
| parser.add_argument("--warning", "-w", required=True, type=int) | ||
| parser.add_argument("--critical", "-c", required=True, type=int) | ||
| args = parser.parse_args() | ||
| if args.url== "": | ||
| usage() | ||
| return 3, "invalid parameter" | ||
| url = args.url | ||
| warning = int(args.warning / 60) | ||
| critical = int(args.critical / 60) | ||
| return check_crl(url, int(warning), int(critical)) | ||
|
|
||
| if __name__ == "__main__": | ||
|
jherbel marked this conversation as resolved.
|
||
| exitcode, info = main() | ||
| sys.stdout.write('%s\n' % info) | ||
| sys.exit(exitcode) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
| # Copyright (C) 2019 tribe29 GmbH - License: GNU General Public License v2 | ||
| # This file is part of Checkmk (https://checkmk.com). It is subject to the terms and | ||
| # conditions defined in the file COPYING, which is part of this source code package. | ||
|
|
||
| import pytest # type: ignore[import] | ||
| from testlib import ActiveCheck # type: ignore[import] | ||
|
|
||
| pytestmark = pytest.mark.checks | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("params,expected_args", [ | ||
| (("foo", 222, 111, "bar", {}), ["--url=foo", "--warn=222", "--crit=111"]), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to the valuespec, you expect a dict here, not a tuple. Accordingly, this test failed in the last travis run. |
||
| ]) | ||
| def test_check_crl_argument_parsing(params, expected_args): | ||
| """Tests if all required arguments are present.""" | ||
| active_check = ActiveCheck("check_crl") | ||
| assert active_check.run_argument_function(params) == expected_args | ||
Uh oh!
There was an error while loading. Please reload this page.