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 # SNMP Configuration
This plugin is intended to help you keep track of the SNMP configuration CheckMK is using to monitor your hosts.\ 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