Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions checkman/check_crl
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.
27 changes: 27 additions & 0 deletions checks/check_crl
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
Comment thread
jherbel marked this conversation as resolved.


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,
}
30 changes: 30 additions & 0 deletions cmk/gui/plugins/wato/active_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2490,3 +2490,33 @@ def _valuespec_active_checks_elasticsearch_query():
name="active_checks:elasticsearch_query",
valuespec=_valuespec_active_checks_elasticsearch_query,
))


def _valuespec_active_checks_crl() -> Dictionary:
return Dictionary(
title=_("Check CRL expiry"),
help=_("Checks if a Certificate Revocation List is still valid"),
optional_keys=[],
elements=[("time",
Tuple(title=_("Time left"),
help=_("These levels make the check go warning or critical whenever the "
"remaining validity of the monitored CRL is too low."),
elements=[
Age(title=_("warning at"),
display=["days", "hours", "minutes"],
default_value=604800),
Age(title=_("critical at"),
display=["days", "hours", "minutes"],
default_value=172800)
])),
("url", TextAscii(title=_('Certificate Revocation List URL'),
allow_empty=False))])


rulespec_registry.register(
HostRulespec(
group=RulespecGroupActiveChecks,
match_type="all",
name="active_checks:crl",
valuespec=_valuespec_active_checks_crl,
))
136 changes: 136 additions & 0 deletions omd/packages/nagios/skel/local/lib/nagios/plugins/check_crl
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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adjust file header please

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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:
RaymiiOrg/nagios#6
I am not saying that you should include this PR here, I am just trying to understand under what conditions this will fail and if this could be avoided by using for example open(..., mode="rb") or something.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, we still need some clarification

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please take a look at cmk.utils.render.Age for this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check cmk.utils.render.Age

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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__":
Comment thread
jherbel marked this conversation as resolved.
exitcode, info = main()
sys.stdout.write('%s\n' % info)
sys.exit(exitcode)
19 changes: 19 additions & 0 deletions tests/unit/checks/test_check_crl.py
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"]),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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