diff --git a/agents/plugins/selinux b/agents/plugins/selinux index 13e90ea..c379edd 100644 --- a/agents/plugins/selinux +++ b/agents/plugins/selinux @@ -1,13 +1,20 @@ #!/bin/bash -# -# Check SELinux status -# SELinux has three modes: -# - permissive -# - enforcing -# - disabled +# -*- encoding: utf-8; py-indent-offset: 4 -*- +# 2024 Marius Pana -# we are not looking at SELINUXPOLICY - although it may be of interest -# in the future +# Reason for this no-op: shellcheck disable=... before the first command disables the error for the +# entire script. +: + +# SELinux status: enabled +# SELinuxfs mount: /sys/fs/selinux +# SELinux root directory: /etc/selinux +# Loaded policy name: targeted +# Current mode: permissive +# Mode from config file: permissive +# Policy MLS status: enabled +# Policy deny_unknown status: allowed +# Max kernel policy version: 31 if command sestatus > /dev/null ; then # Selinux status diff --git a/checks/selinux b/checks/selinux deleted file mode 100644 index 05a73e9..0000000 --- a/checks/selinux +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -# -# Author: Marius Pana - -factory_settings["selinux_default_levels"] = { - "modedisabled" : 2, - "curmodepermissive" : 1, - "filemodepermissive" : 2, -} - -def inventory_selinux(info): - inventory = [] - for line in info: - yield None, {} - -def check_selinux(item, params, info): - for line in info: - state = 0 - if line[0] == 'disabled': - state = params["modedisabled"] - return (state, "SELinux is disabled") - elif line[1] == "enforcing" and line[2] == "enforcing": - return(state, "SELinux is enabled and enforcing.") - elif line[1] == "enforcing" and line[2] == "permissive": - return(state, "SELinux is enforcing but config file is in permissive mode.") - elif line[1] == "permissive" and line[2] == "enforcing": - state = params["curmodepermissive"] - return (state, "SELinux is in permissive mode but config file is enforcing.") - elif line[2] == "permissive": - state = params["filemodepermissive"] - return (state, "SELinux is in permissive mode.") - else: - return(3, "SELinux not found in agent output") - -check_info["selinux"] = { - "inventory_function" : inventory_selinux, - "check_function" : check_selinux, - "has_perfdata" : False, - "service_description" : "SELinux state", - "default_levels_variable" : "selinux_default_levels", - 'group': 'selinux', -} \ No newline at end of file diff --git a/info b/info index 8053b52..9a722f6 100644 --- a/info +++ b/info @@ -1,18 +1,14 @@ {'author': 'Marius Pana', 'description': 'Check SELinux status', 'download_url': 'https://code.spearhead.cloud/Spearhead/check_mk-check-selinux', - 'files': {'agents': ['plugins/selinux'], - 'bin': [], - 'checkman': ['selinux'], - 'checks': ['selinux'], - 'doc': [], - 'inventory': [], - 'lib': [], - 'notifications': [], - 'pnp-templates': [], - 'web': ['plugins/wato/selinux_check_parameters.py']}, + 'files': {'agent_based': ['selinux.py'], + 'agents': ['plugins/selinux'], + 'lib': ['python3/cmk/base/cee/plugins/bakery/selinux_bakery.py'], + 'web': ['plugins/wato/selinux_parameters.py', + 'plugins/wato/selinuxbakery_bakery.py']}, 'name': 'selinux', 'title': 'Check SELinux', - 'version': '1.0', - 'version.min_required': '1.2.8p27', - 'version.packaged': '1.2.8p27'} \ No newline at end of file + 'version': '1.1.0', + 'version.min_required': '2.2.0p0', + 'version.packaged': '2.2.0p8', + 'version.usable_until': None} \ No newline at end of file diff --git a/lib/python3/cmk/base/cee/plugins/bakery/selinux_bakery.py b/lib/python3/cmk/base/cee/plugins/bakery/selinux_bakery.py new file mode 100644 index 0000000..5ac9757 --- /dev/null +++ b/lib/python3/cmk/base/cee/plugins/bakery/selinux_bakery.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# 2024 Marius Pana + +from pathlib import Path +from typing import Any + +from .bakery_api.v1 import ( + OS, + DebStep, + RpmStep, + SolStep, + Plugin, + PluginConfig, + SystemBinary, + WindowsConfigEntry, + register, + FileGenerator, + ScriptletGenerator, + WindowsConfigGenerator, + quote_shell_string, +) + +def get_selinux_files(conf: Any) -> FileGenerator: + yield Plugin(base_os=OS.LINUX, source=Path("selinux")) + +register.bakery_plugin( + name="selinux", + files_function=get_selinux_files, +) \ No newline at end of file diff --git a/lib/python3/cmk/base/plugins/agent_based/selinux.py b/lib/python3/cmk/base/plugins/agent_based/selinux.py new file mode 100644 index 0000000..a9b71da --- /dev/null +++ b/lib/python3/cmk/base/plugins/agent_based/selinux.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# -*- encoding: utf-8; py-indent-offset: 4 -*- +# 2024 Marius Pana + +from .agent_based_api.v1 import * + +def discover_selinux(section): + #for line in info: + # yield None, {} + #print(Service) + yield Service() + +def check_selinux(params, section): + for line in section: + if line[0] == 'disabled': + yield Result(state=State(params["modedisabled"]), summary="SELinux is disabled") + elif line[1] == "enforcing" and line[2] == "enforcing": + yield Result(state=State.OK, summary="SELinux is enabled and enforcing") + elif line[1] == "enforcing" and line[2] == "permissive": + yield Result(state=State.WARN, summary="SELinux is enforcing but config file is in permissive mode.") + elif line[1] == "permissive" and line[2] == "enforcing": + yield Result(state=State(params["curmodepermissive"]), summary="SELinux is in permissive mode but config file is enforcing.") + elif line[2] == "permissive": + yield Result(state=State(params["curmodepermissive"]), summary="SELinux is in permissive mode.") + else: + yield Result(state=State.WARN, summary="SELinux not found in agent output") + +register.check_plugin( + name="selinux", + service_name="SELinux state", + discovery_function=discover_selinux, + check_function=check_selinux, + check_ruleset_name="selinux", + check_default_parameters = {"modedisabled": 2, "curmodepermissive" : 1, "filemodepermissive" : 2} +) \ No newline at end of file diff --git a/web/plugins/wato/selinux_check_parameters.py b/web/plugins/wato/selinux_check_parameters.py index 54783ad..89b93e4 100644 --- a/web/plugins/wato/selinux_check_parameters.py +++ b/web/plugins/wato/selinux_check_parameters.py @@ -1,12 +1,24 @@ #!/usr/bin/python # -*- encoding: utf-8; py-indent-offset: 4 -*- -# 2018 Marius Pana +# 2024 Marius Pana -register_check_parameters( - subgroup_os, - "selinux", - _("SELinux"), - Dictionary( +from cmk.gui.i18n import _ +from cmk.gui.valuespec import ( + Dictionary, + # Integer, + # TextInput, +) +from cmk.gui.plugins.wato.utils import ( + CheckParameterRulespecWithoutItem, + rulespec_registry, + RulespecGroupCheckParametersOperatingSystem, +) + +#def _item_valuespec_selinux(): +# return TextInput(title="SELinux state", help="SELinux state configuration") + +def _parameter_valuespec_selinux(): + return Dictionary( elements = [ ( "modedisabled", MonitoringState( @@ -23,8 +35,15 @@ register_check_parameters( title = _("State when SELinux file mode is permissive"), default_value = 2, )), - ] - ), - None, - match_type = "dict", -) + ], + ) + +rulespec_registry.register( + CheckParameterRulespecWithoutItem( + check_group_name="selinux", + group=RulespecGroupCheckParametersOperatingSystem, + match_type="dict", + #item_spec=_item_valuespec_selinux, + parameter_valuespec=_parameter_valuespec_selinux, + title=lambda: _("SELinux states"), + )) \ No newline at end of file diff --git a/web/plugins/wato/selinuxbakery_bakery.py b/web/plugins/wato/selinuxbakery_bakery.py new file mode 100644 index 0000000..a5488b1 --- /dev/null +++ b/web/plugins/wato/selinuxbakery_bakery.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# -*- encoding: utf-8; py-indent-offset: 4 -*- +# 2024 Marius Pana + +from cmk.gui.i18n import _ +from cmk.gui.plugins.wato import ( + HostRulespec, + rulespec_registry, +) +from cmk.gui.cee.plugins.wato.agent_bakery.rulespecs.utils import RulespecGroupMonitoringAgentsAgentPlugins +from cmk.gui.valuespec import ( + DropdownChoice +) + + +def _valuespec_agent_config_selinux(): + return DropdownChoice( + title=_("Deploy SELinux (Linux)"), + help=_("Hosts configured via this rule get the selinux plugin " "deployed."), + choices=[ + (True, _("Deploy selinux plugin")), + (None, _("Do not deploy selinux plugin")), + ], + ) + +rulespec_registry.register( + HostRulespec( + group=RulespecGroupMonitoringAgentsAgentPlugins, + name="agent_config:selinux", + valuespec=_valuespec_agent_config_selinux, + )) \ No newline at end of file