Merge branch 'develop-issue_4' into 'master'
Neuer Check: TLS-Zertifikat See merge request tools/heimdall!4
This commit is contained in:
commit
c71e4a6bd4
|
|
@ -571,6 +571,49 @@
|
||||||
"parameters"
|
"parameters"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "check 'tls_certificate'",
|
||||||
|
"type": "object",
|
||||||
|
"unevaluatedProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"tls_certificate"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"host": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"strict": {
|
||||||
|
"description": "whether a violation of this check shall be leveled as critical instead of concerning",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"expiry_threshold": {
|
||||||
|
"description": "in days; allowed amount of valid days before the certificate expires",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"integer"
|
||||||
|
],
|
||||||
|
"default": 7,
|
||||||
|
"minimum": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"host"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"parameters"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": "check 'http_request'",
|
"title": "check 'http_request'",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"includes": [
|
"includes": [
|
||||||
"script.hmdl.json",
|
"tls_certificate.hmdl.json"
|
||||||
"file_state.hmdl.json",
|
|
||||||
"generic_remote.hmdl.json"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
examples/tls_certificate.hmdl.json
Normal file
19
examples/tls_certificate.hmdl.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"checks": [
|
||||||
|
{
|
||||||
|
"name": "test1",
|
||||||
|
"kind": "tls_certificate",
|
||||||
|
"parameters": {
|
||||||
|
"host": "greenscale.de",
|
||||||
|
"expiry_threshold": 50
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test2",
|
||||||
|
"kind": "tls_certificate",
|
||||||
|
"parameters": {
|
||||||
|
"host": "chemnitz-gesundheit.de"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
"checks.file_state.timestamp_implausible": "Datei ist scheinbar aus der Zukunft",
|
"checks.file_state.timestamp_implausible": "Datei ist scheinbar aus der Zukunft",
|
||||||
"checks.file_state.too_old": "Datei ist zu alt",
|
"checks.file_state.too_old": "Datei ist zu alt",
|
||||||
"checks.file_state.too_big": "Datei ist zu groß",
|
"checks.file_state.too_big": "Datei ist zu groß",
|
||||||
|
"checks.tls_certificate.not_obtainable": "TLS-Zertifikat nicht abrufbar; evtl. bereits ausgelaufen",
|
||||||
|
"checks.tls_certificate.expires_soon": "TLS-Zertifikat läuft bald aus",
|
||||||
"checks.generic_remote.overflow": "Laufwerk fast voll",
|
"checks.generic_remote.overflow": "Laufwerk fast voll",
|
||||||
"checks.http_request.request_failed": "HTTP-Abfrage fehlgeschlagen",
|
"checks.http_request.request_failed": "HTTP-Abfrage fehlgeschlagen",
|
||||||
"checks.http_request.status_code_mismatch": "Status-Code {{status_code_actual}} stimmt nicht mit dem erwarteten Wert {{status_code_expected}} überein",
|
"checks.http_request.status_code_mismatch": "Status-Code {{status_code_actual}} stimmt nicht mit dem erwarteten Wert {{status_code_expected}} überein",
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
"checks.file_state.timestamp_implausible": "file is apparently from the future",
|
"checks.file_state.timestamp_implausible": "file is apparently from the future",
|
||||||
"checks.file_state.too_old": "file is too old",
|
"checks.file_state.too_old": "file is too old",
|
||||||
"checks.file_state.too_big": "file is too big",
|
"checks.file_state.too_big": "file is too big",
|
||||||
|
"checks.tls_certificate.not_obtainable": "TLS certificate not obtainable; maybe already expired",
|
||||||
|
"checks.tls_certificate.expires_soon": "TLS certificate will expire soon",
|
||||||
"checks.generic_remote.overflow": "disk drive almost full",
|
"checks.generic_remote.overflow": "disk drive almost full",
|
||||||
"checks.http_request.request_failed": "HTTP request failed",
|
"checks.http_request.request_failed": "HTTP request failed",
|
||||||
"checks.http_request.status_code_mismatch": "actual status code {{status_code_actual}} does not match expected value {{status_code_expected}}",
|
"checks.http_request.status_code_mismatch": "actual status code {{status_code_actual}} does not match expected value {{status_code_expected}}",
|
||||||
|
|
|
||||||
121
source/logic/checks/tls_certificate.py
Normal file
121
source/logic/checks/tls_certificate.py
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
'''
|
||||||
|
todo: allow_self_signed
|
||||||
|
todo: allow_bad_domain
|
||||||
|
todo:
|
||||||
|
'''
|
||||||
|
class implementation_check_kind_tls_certificate(interface_check_kind):
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def parameters_schema(self):
|
||||||
|
return {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": False,
|
||||||
|
"properties": {
|
||||||
|
"host": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"type": "integer",
|
||||||
|
"default": 443
|
||||||
|
},
|
||||||
|
"strict": {
|
||||||
|
"description": "whether a violation of this check shall be leveled as critical instead of concerning",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": True
|
||||||
|
},
|
||||||
|
"expiry_threshold": {
|
||||||
|
"description": "in days; allowed amount of valid days before the certificate expires",
|
||||||
|
"type": ["null", "integer"],
|
||||||
|
"default": 7,
|
||||||
|
"minimum": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"host"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def normalize_conf_node(self, node):
|
||||||
|
if (not "host" in node):
|
||||||
|
raise ValueError("missing mandatory field 'host'")
|
||||||
|
else:
|
||||||
|
return dict_merge(
|
||||||
|
{
|
||||||
|
"strict": True,
|
||||||
|
"port": 443,
|
||||||
|
"expiry_threshold": 7,
|
||||||
|
# "allow_self_signed": False,
|
||||||
|
# "allow_bad_domain": False,
|
||||||
|
},
|
||||||
|
node
|
||||||
|
)
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def run(self, parameters):
|
||||||
|
context = _ssl.create_default_context()
|
||||||
|
try:
|
||||||
|
socket = _socket.create_connection((parameters["host"], parameters["port"], ))
|
||||||
|
socket_wrapped = context.wrap_socket(socket, server_hostname = parameters["host"])
|
||||||
|
version = socket_wrapped.version()
|
||||||
|
data = socket_wrapped.getpeercert(False)
|
||||||
|
except _ssl.SSLCertVerificationError as error:
|
||||||
|
version = None
|
||||||
|
data = None
|
||||||
|
if (data is None):
|
||||||
|
return {
|
||||||
|
"condition": (
|
||||||
|
enum_condition.critical
|
||||||
|
if parameters["strict"] else
|
||||||
|
enum_condition.concerning
|
||||||
|
),
|
||||||
|
"info": {
|
||||||
|
"host": parameters["host"],
|
||||||
|
"port": parameters["port"],
|
||||||
|
"faults": [
|
||||||
|
translation_get("checks.tls_certificate.not_obtainable"),
|
||||||
|
],
|
||||||
|
"data": {
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
# version == "TLSv1.3"
|
||||||
|
expiry_timestamp = _ssl.cert_time_to_seconds(data["notAfter"])
|
||||||
|
current_timestamp = get_current_timestamp()
|
||||||
|
days = _math.ceil((expiry_timestamp - current_timestamp) / (60 * 60 * 24))
|
||||||
|
if (days <= parameters["expiry_threshold"]):
|
||||||
|
return {
|
||||||
|
"condition": (
|
||||||
|
enum_condition.critical
|
||||||
|
if parameters["strict"] else
|
||||||
|
enum_condition.concerning
|
||||||
|
),
|
||||||
|
"info": {
|
||||||
|
"host": parameters["host"],
|
||||||
|
"port": parameters["port"],
|
||||||
|
"faults": [
|
||||||
|
translation_get("checks.tls_certificate.expires_soon"),
|
||||||
|
],
|
||||||
|
"data": {
|
||||||
|
"expiry_timestamp": expiry_timestamp,
|
||||||
|
"days": days,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
"condition": enum_condition.ok,
|
||||||
|
"info": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -121,6 +121,7 @@ def main():
|
||||||
check_kind_implementations = {
|
check_kind_implementations = {
|
||||||
"script": implementation_check_kind_script(),
|
"script": implementation_check_kind_script(),
|
||||||
"file_state": implementation_check_kind_file_state(),
|
"file_state": implementation_check_kind_file_state(),
|
||||||
|
"tls_certificate": implementation_check_kind_tls_certificate(),
|
||||||
"http_request": implementation_check_kind_http_request(),
|
"http_request": implementation_check_kind_http_request(),
|
||||||
"generic_remote" : implementation_check_kind_generic_remote(),
|
"generic_remote" : implementation_check_kind_generic_remote(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import sys as _sys
|
import sys as _sys
|
||||||
import os as _os
|
import os as _os
|
||||||
import subprocess as _subprocess
|
import subprocess as _subprocess
|
||||||
|
import math as _math
|
||||||
import hashlib as _hashlib
|
import hashlib as _hashlib
|
||||||
import tempfile as _tempfile
|
import tempfile as _tempfile
|
||||||
import argparse as _argparse
|
import argparse as _argparse
|
||||||
|
|
@ -11,3 +12,5 @@ import time as _time
|
||||||
import datetime as _datetime
|
import datetime as _datetime
|
||||||
import smtplib as _smtplib
|
import smtplib as _smtplib
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
|
import ssl as _ssl
|
||||||
|
import socket as _socket
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ def main():
|
||||||
_os.path.join(dir_source, "logic", "checks", "_interface.py"),
|
_os.path.join(dir_source, "logic", "checks", "_interface.py"),
|
||||||
_os.path.join(dir_source, "logic", "checks", "script.py"),
|
_os.path.join(dir_source, "logic", "checks", "script.py"),
|
||||||
_os.path.join(dir_source, "logic", "checks", "file_state.py"),
|
_os.path.join(dir_source, "logic", "checks", "file_state.py"),
|
||||||
|
_os.path.join(dir_source, "logic", "checks", "tls_certificate.py"),
|
||||||
_os.path.join(dir_source, "logic", "checks", "http_request.py"),
|
_os.path.join(dir_source, "logic", "checks", "http_request.py"),
|
||||||
_os.path.join(dir_source, "logic", "checks", "generic_remote.py"),
|
_os.path.join(dir_source, "logic", "checks", "generic_remote.py"),
|
||||||
_os.path.join(dir_source, "logic", "channels", "_interface.py"),
|
_os.path.join(dir_source, "logic", "channels", "_interface.py"),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue