Collection of CheckMK checks (see https://checkmk.com/). All checks and plugins are provided as is. Absolutely no warranty. Send any comments to thl-cmk[at]outlook[dot]com

Skip to content
Snippets Groups Projects
Commit 451f44a1 authored by thl-cmk's avatar thl-cmk :flag_na:
Browse files

update project

parent 1dfc7ab9
No related branches found
No related tags found
No related merge requests found
[PACKAGE]: ../../raw/master/snmp_state-0.0.3-20230802.mkp "snmp_state-0.0.3-20230802.mkp"
[PACKAGE]: ../../raw/master/snmp_configuration-0.0.5-20230804.mkp "snmp_configuration-0.0.5-20230804.mkp"
# SNMP Configuration
This plugin is intended to help you keep track of the SNMP configuration CheckMK is using to monitor your hosts.\
......
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# License: GNU General Public License v2
#
# Author: thl-cmk[at]outlook[dot]com
# URL : https://thl-cmk.hopto.org
# Date : 2023-06-28
# File : snmp_configuration.py
#
# Monitor snmp version used by CMK for a host object
#
# 2023-06-28: initial release
# 2023-07-09: added WATO parameters
# 2023-07-11: added check key length, key complexity, use of default keys
# 2023-08-04: renamed from snmp_version to snmp_configuration
# streamlined function parameters
# added option to check for reversed keys in default keys list
# added report only option
# added top level _check_key function
# added check for duplicate char in key
# ToDo
# maybe add number of repeated chars?
import re
from typing import List
from cmk.base.check_api import host_name
from cmk.base.config import get_config_cache
from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
DiscoveryResult,
CheckResult,
StringTable,
)
from cmk.base.plugins.agent_based.agent_based_api.v1 import (
register,
Service,
SNMPTree,
Result,
State,
exists,
)
def _check_expected(value, message: str, state: int, report_only: bool, excepted: List):
if report_only:
state = 0
if value in excepted:
yield Result(state=State.OK, summary=f'{message}: {value}')
else:
yield Result(state=State(state), summary=f'{message} {value}')
def _result(message: str, state: int, report_only: bool):
if report_only:
yield Result(state=State.OK, summary=message)
else:
yield Result(state=State(state), notice=message)
def _check_key_length(key: str, message: str, state: int, report_only: bool, min_length: int):
if len(key) < min_length:
yield from _result(
state=state, report_only=report_only, message=f'{message} length below {min_length}'
)
else:
yield Result(state=State.OK, notice=f'{message} length is not below {min_length}')
def _check_default_key(
key: str, message: str, state: int, report_only: bool, default_keys: List[str], reversed_key: bool
):
if key.lower() in default_keys:
yield from _result(state=state, report_only=report_only, message=f'{message} uses default value')
elif reversed_key and key.lower()[::-1] in default_keys:
yield from _result(state=state, report_only=report_only, message=f'{message} uses default value (reverse)')
else:
yield Result(state=State.OK, notice=f'{message} is not using default keys')
def _check_key_complexity(key: str, message: str, state: int, report_only: bool, regex: List[str]):
_regex = ''.join(regex)
if not re.search(_regex, key):
yield from _result(state=state, report_only=report_only, message=f'{message} complexity is not met')
else:
yield Result(state=State.OK, notice=f'{message} complexity is met.')
def _check_repeated_chars(key: str, message: str, state: int, report_only: bool):
_regex = '(.)\\1{1}' # {x} number of repetitions
if re.search(_regex, key):
# re.search(_regex, key).group() gives the repeated chars
yield from _result(
state=state, report_only=report_only,
message=f'{message} has repeated chars'
)
else:
yield Result(state=State.OK, notice=f'{message} has no repeated chars')
def _check_key(
key: str,
message: str,
report_only: bool,
key_length_state: int,
key_length_min: int,
default_key_state: int,
default_key_list: List[str],
default_key_reversed: bool,
complexity_state: int,
complexity_regex: List[str],
complexity_repeated: bool,
):
if key_length_min > 0:
yield from _check_key_length(key, message, key_length_state, report_only, key_length_min)
if default_key_list:
yield from _check_default_key(
key, message, default_key_state, report_only, default_key_list, default_key_reversed
)
if complexity_regex:
yield from _check_key_complexity(key, message, complexity_state, report_only, complexity_regex)
if complexity_repeated:
yield from _check_repeated_chars(key, message, complexity_state, report_only)
def parse_snmp_configuration(string_table: StringTable):
return string_table
def discovery_snmp_configuration(section) -> DiscoveryResult:
yield Service()
def check_snmp_configuration(params, section) -> CheckResult:
config_cache = get_config_cache()
snmp_host = False
report_only = params['report_only']
try:
# test for CMK 2.2.x
snmp_host = config_cache.is_snmp_host(host_name())
snmp_credentials = config_cache._snmp_credentials(host_name())
snmp_backend = config_cache.get_snmp_backend(host_name()).value
snmp_version1 = config_cache._is_host_snmp_v1(host_name())
except AttributeError:
# try cmk 2.0.x - 2.1.x
host_config = config_cache.get_host_config(host_name())
snmp_config = host_config.snmp_config(None)
snmp_credentials = snmp_config.credentials
snmp_backend = snmp_config.snmp_backend.value
snmp_version1 = host_config._is_host_snmp_v1()
if snmp_credentials:
snmp_host = True
if snmp_host:
snmp_version = '1' if snmp_version1 else '2c' if type(snmp_credentials) is str else '3'
excepted, state = params['snmp_version']
yield from _check_expected(snmp_version, 'Version', state, report_only, excepted)
excepted, state = params['snmp_backend']
yield from _check_expected(snmp_backend.lower(), 'Backend', state, report_only, excepted)
if snmp_version == '3':
excepted, state = params['v3_level']
yield from _check_expected(snmp_credentials[0].lower(), 'Level', state, report_only, excepted)
if len(snmp_credentials) > 2:
excepted, state = params['v3_authentication']
excepted = list(map(str.upper, excepted))
yield from _check_expected(snmp_credentials[1].upper(), 'Authentication', state, report_only, excepted)
try:
snmp_encryption = snmp_credentials[4]
except IndexError:
pass
else:
excepted, state = params['v3_encryption']
excepted = list(map(str.upper, excepted))
yield from _check_expected(snmp_encryption.upper(), 'Encryption', state, report_only, excepted)
min_key_length, state_min_key = params['min_key_length']
default_keys, reversed_keys, state_default_key = params['default_keys']
default_keys = list(map(str.lower, default_keys))
key_complexity, repeated_chars, state_key_complexity = params['key_complexity']
if snmp_version != '3':
message = 'Community string'
yield from _check_key(
key=snmp_credentials,
message=message,
report_only=report_only,
key_length_state=state_min_key,
key_length_min=min_key_length,
default_key_state=state_default_key,
default_key_list=default_keys,
default_key_reversed=reversed_keys,
complexity_state=state_key_complexity,
complexity_regex=key_complexity,
complexity_repeated=repeated_chars,
)
else:
if len(snmp_credentials) > 2:
message = 'Authentication key'
yield from _check_key(
key=snmp_credentials[3],
message=message,
report_only=report_only,
key_length_state=state_min_key,
key_length_min=min_key_length,
default_key_state=state_default_key,
default_key_list=default_keys,
default_key_reversed=reversed_keys,
complexity_state=state_key_complexity,
complexity_regex=key_complexity,
complexity_repeated=repeated_chars,
)
if len(snmp_credentials) == 6:
message = 'Encryption key'
yield from _check_key(
key=snmp_credentials[5],
message=message,
report_only=report_only,
key_length_state=state_min_key,
key_length_min=min_key_length,
default_key_state=state_default_key,
default_key_list=default_keys,
default_key_reversed=reversed_keys,
complexity_state=state_key_complexity,
complexity_regex=key_complexity,
complexity_repeated=repeated_chars,
)
if snmp_credentials[3] != snmp_credentials[5]:
yield Result(state=State.OK, notice=F'Authentication and Encryption key are different')
else:
yield Result(
state=State(params['auth_enc_key_identical']),
notice=F'Authentication and Encryption key are identical'
)
else:
yield Result(state=State.OK, summary='No SNMP host')
register.snmp_section(
name='snmp_configuration',
parse_function=parse_snmp_configuration,
fetch=SNMPTree(
base='.1.3.6.1.2.1.1', #
oids=[
'1', # sysDescr
]),
detect=exists('.1.3.6.1.2.1.1.1.0', ), # sysDescr
)
register.check_plugin(
name='snmp_configuration',
service_name='SNMP Configuration',
discovery_function=discovery_snmp_configuration,
check_function=check_snmp_configuration,
check_default_parameters={
'report_only': False,
'snmp_version': (['3', 1]),
'v3_level': (['authpriv'], 1),
'v3_authentication': (['sha', 'sha-224', 'sha-256', 'sha-384', 'sha-512'], 1),
'v3_encryption': (['aes'], 1),
'snmp_backend': (['inline', 'classic'], 1),
'default_keys': (['public', 'private'], True, 1),
'min_key_length': (10, 1),
'auth_enc_key_identical': 1,
'key_complexity': (['(?=.*\\d)', '(?=.*[a-z])', '(?=.*[A-Z])', '(?=.*\\W)', '(?=.{10,})'], True, 1),
},
check_ruleset_name='snmp_configuration',
)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# License: GNU General Public License v2
# Author: thl-cmk[at]outlook[dot]com
# URL : https://thl-cmk.hopto.org
# Date : 2023-07-09
# File : snmp_configuration.py
#
# WATO file for snmp_configuration check plugin
#
# 2023-07-09: initial release
# 2023-08-04: renamed from snmp_version to snmp_configuration
# added options for report only, reversed keys, no repeated chars
# optimized layout
# moved rule set from Networking to Applications, Processes & Services
from cmk.gui.i18n import _
from cmk.gui.valuespec import (
Dictionary,
MonitoringState,
Tuple,
ListChoice,
Integer,
ListOfStrings,
FixedValue,
Checkbox,
)
from cmk.gui.plugins.wato.utils import (
CheckParameterRulespecWithoutItem,
rulespec_registry,
RulespecGroupCheckParametersApplications,
)
def _parameter_valuespec_snmp_configuration():
return Dictionary(
elements=[
('report_only',
FixedValue(
value=True,
title=_('Report only'),
totext=_(''),
help=_('If enabled the check will not create any alerts (WAR/CRIT)'),
)),
('snmp_version',
Tuple(
title=_('SNMP Version'),
elements=[
ListChoice(
choices=[
('1', 'Version 1'),
('2c', 'Version 2c'),
('3', 'Version 3')
],
allow_empty=False,
help=_('Select excepted SNMP versions. Default is "Version 3".'),
default_value=['3'],
),
MonitoringState(
label=_('Monitoring state if version not in list'),
default_value=1,
)
])),
('v3_level',
Tuple(
title=_('SNMP v3 level'),
elements=[
ListChoice(
choices=[
('authpriv', 'authentication and privacy'),
('authnopriv', 'authentication and no privacy'),
('noauthnopriv', 'no authentication and no privacy'),
],
allow_empty=False,
help=_('Select excepted SNMP v3 protocol level. Default is "authentication and privacy".'),
default_value=['authpriv'],
),
MonitoringState(
label=_('Monitoring state if level is not list'),
default_value=1,
)
])),
('v3_authentication',
Tuple(
title=_('SNMP v3 authentication'),
elements=[
ListChoice(
choices=[
('md5', 'MD5'),
('sha', 'SHA'),
('sha-224', 'SHA-224'),
('sha-256', 'SHA-256'),
('sha-384', 'SHA-384'),
('sha-512', 'SHA-512'),
],
allow_empty=False,
help=_('Select excepted SNMP v3 authentication. Default is "SHA*".'),
default_value=['sha', 'sha-224', 'sha-256', 'sha-384', 'sha-512'],
),
MonitoringState(
label=_('Monitoring state if authentication is not in list'),
default_value=1,
)
])),
('v3_encryption',
Tuple(
title=_('SNMP v3 encryption'),
elements=[
ListChoice(
choices=[
('des', 'DES'),
('aes', 'AES-128'),
],
allow_empty=False,
help=_('Select excepted encryption. Default is "AES-128".'),
default_value=['aes'],
),
MonitoringState(
label=_('Monitoring state if encryption is not in list'),
default_value=1,
)
])),
('snmp_backend',
Tuple(
title=_('SNMP backend'),
elements=[
ListChoice(
choices=[
('inline', 'Inline'),
('classic', 'Classic'),
('storedwalk', 'Stored walk')
],
allow_empty=False,
help=_('Select excepted SNMP backend. Default is "Inline/Classic".'),
default_value=['inline', 'classic'],
),
MonitoringState(
label=_('Monitoring state if backend not in list'),
default_value=1,
)
])),
('min_key_length',
Tuple(
title=_('Minimal key length'),
elements=[
Integer(
minvalue=0,
help=_(
'Minimal expected Community string/key length. '
'Use "0" to disable this check. Default is "10".'
),
default_value=10,
),
MonitoringState(
label=_('Monitoring state if key length below minimal key length'),
help=_(
'Set the monitoring state when the length of the Community string (SNMP v1/2c) '
'or the authentication/encryption key (SNMP v3) is below min. length. Default is WARN'
),
default_value=1,
)
])),
('auth_enc_key_identical',
MonitoringState(
title=_('Monitoring state when authentication and encryption keys are identical'),
help=_(
'Set the monitoring state when authentication key and encryption key are identical. '
'This setting is for SNMP v3 only. Default is WARN.'
),
default_value=1,
)),
('default_keys',
Tuple(
title=_('Check default key values'),
elements=[
ListOfStrings(
help=_(
'List of default Community strings/keys to check against. Default is "public, private".'
),
default_value=['public', 'private'],
),
Checkbox(
label=_('Check reversed keys'),
help=_('This will also check for keys in reverse. So "cilbup" will match "public".'),
default_value=True,
),
MonitoringState(
label=_('Monitoring state if key used is a default key'),
help=_(
'Set the monitoring state when the key used is in the list of default keys. '
'Default is WARN'
),
default_value=1,
)
])),
('key_complexity',
Tuple(
title=_('Key complexity'),
elements=[
ListChoice(
choices=[
('(?=.*\\d)', 'Digit'),
('(?=.*[a-z])', 'Lowercase'),
('(?=.*[A-Z])', 'Uppercase'),
('(?=.*\\W)', 'Special')
],
help=_(
'Select expected character types in the Community string or authentication/encryption key.'
' Default is "Number, Lower case, Upper case, Special".'),
default_value=['(?=.*\\d)', '(?=.*[a-z])', '(?=.*[A-Z])', '(?=.*\\W)'],
),
Checkbox(
label=_('no repeated chars'),
help=_('This will also check if the key contains repeated characters..'),
default_value=True,
),
MonitoringState(
label=_('Monitoring state if key complexity not met'),
default_value=1,
)
])),
])
rulespec_registry.register(
CheckParameterRulespecWithoutItem(
check_group_name='snmp_configuration',
group=RulespecGroupCheckParametersApplications,
match_type='dict',
parameter_valuespec=_parameter_valuespec_snmp_configuration,
title=lambda: _('Checkmk SNMP Configuration'),
))
{'author': 'Th.L. (thl-cmk[at]outlook[dot]com)',
'description': 'Monitors SNMP configuration used by CheckMK to access '
'monitored hosts.\n'
'\n'
'This check is intended to help keep track on the SNMP '
'configuration used by CheckMK. \n'
'\n'
'It will create an alert if old SNMP versions (or bad '
'parameters) are in use.\n'
'All this can be configured via WATO.\n',
'download_url': 'https://thl-cmk.hopto.org',
'files': {'agent_based': ['snmp_configuration.py'],
'gui': ['wato/check_parameters/snmp_configuration.py']},
'name': 'snmp_configuration',
'title': 'SNMP Configuration',
'version': '0.0.5-20230804',
'version.min_required': '2.0.0b1',
'version.packaged': '2.2.0p7',
'version.usable_until': None}
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment