Update Azure Keyvault to use the new plugin API in CheckMK 2.3+

This commit is contained in:
Marsell Kukuljevic 2025-10-13 10:32:45 +02:00
parent 33b5055b62
commit 7fb9a07709
9 changed files with 219 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,71 @@
#,!/usr/bin/env python3
# Copyright (C) 2025 Spearhead Systems SRL - License: GNU General Public License v2
import json
from datetime import datetime, timezone
from cmk.agent_based.v2 import Result, Service, State, CheckPlugin, AgentSection
# Convert JSON entries into dictionaries indexed by certificate name.
def parse_keyvault(string_table):
raw_json = ""
cert_data = []
for row in string_table:
line = row[0]
raw_json += line
if line == "]":
cert_data.extend(json.loads(raw_json))
raw_json = ""
lookup = {}
for cert in cert_data:
lookup[cert["name"]] = cert
return lookup
# Produce a list of certificates based on the parsed output.
def discover_keyvault(section):
for name, details in sorted(section.items()):
yield Service(item=name)
# Given a specific certificate, look it up in the parsed output, and produce
# results on that service based upon the certificate's expiry.
def check_keyvault(item, params, section):
warn_days = params.get("warn_days")
crit_days = params.get("crit_days")
cert = section.get(item)
if cert is None:
return
expires = datetime.fromisoformat(cert["attributes"]["expires"])
now = datetime.now(timezone.utc)
remaining_days = (expires - now).days
state = State.OK
if crit_days is not None and remaining_days < crit_days:
state = State.CRIT
elif warn_days is not None and remaining_days < warn_days:
state = State.WARN
yield Result(state=state, summary="Expires in %d days" % remaining_days)
agent_section_azure_keyvault = AgentSection(
name="azure_keyvault",
parse_function=parse_keyvault,
)
check_plugin_azure_keyvault = CheckPlugin(
name="azure_keyvault",
service_name="Azure Keyvault Certificate %s",
check_function=check_keyvault,
check_default_parameters={},
check_ruleset_name="azure_keyvault",
discovery_function=discover_keyvault,
)

View File

@ -0,0 +1,26 @@
#!/bin/bash
# Copyright (C) 2023 Spearhead Systems SRL - License: GNU General Public License v2
az=/usr/bin/az
set -euo pipefail
if [ "$#" -lt 4 ]; then
echo "Usage: $0 <tenant> <user> <password> <vault1> ... [vaultN]" >&2
exit 1
fi
tenant="$1"
user="$2"
password="$3"
vaults="${@:4}"
echo "<<<azure_keyvault:sep(0)>>>"
"$az" login --service-principal --tenant="$tenant" --user="$user" --password="$password" > /dev/null
for vault in $vaults; do
"$az" keyvault certificate list --vault-name="$vault"
done
"$az" logout

View File

@ -0,0 +1,95 @@
#!/usr/bin/env python3
# Copyright (C) 2025 Spearhead Systems SRL - License: GNU General Public License v2
from cmk.rulesets.v1 import Label
from cmk.rulesets.v1.form_specs import Dictionary, DictElement, String, Integer, Password, List, DefaultValue
from cmk.rulesets.v1.rule_specs import SpecialAgent, CheckParameters, HostCondition, Topic, Title, Help
from cmk.rulesets.v1.form_specs.validators import LengthInRange, NumberInRange
def _formspec_azure_keyvault_check():
return Dictionary(
title = Title("Azure Key Vault Certificate Checks"),
elements = {
"warn_days": DictElement(
parameter_form = Integer(
title = Title("Certificate Days to Warn"),
help_text = Help("How many days to warn before a certificate in this key vault will expire"),
prefill = DefaultValue(30),
custom_validate = (NumberInRange(min_value=0),),
),
),
"crit_days": DictElement(
parameter_form = Integer(
title = Title("Certificate Days to Crit"),
help_text = Help("How many days to crit before a certificate in this key vault will expire"),
prefill = DefaultValue(3),
custom_validate = (NumberInRange(min_value=0),),
),
),
},
)
def _formspec_azure_keyvault_discovery():
return Dictionary(
title = Title("Azure Key Vault Certificate Discovery"),
elements = {
"tenant": DictElement(
required = True,
parameter_form = String(
title = Title("Tenant ID / Directory ID"),
custom_validate = (LengthInRange(min_value=1),),
),
),
"client": DictElement(
required = True,
parameter_form = String(
title = Title("Client ID / Application ID"),
custom_validate = (LengthInRange(min_value=1),),
),
),
"secret": DictElement(
required = True,
parameter_form = Password(
title = Title("Client Secret"),
custom_validate = (LengthInRange(min_value=1),),
),
),
"vaults": DictElement(
required = True,
parameter_form = List(
title = Title("Keyvaults"),
add_element_label = Label("Add new keyvault"),
custom_validate = (LengthInRange(min_value=1),),
element_template = String(label=Label("Keyvault")),
),
),
},
)
rule_spec_agent_config_azure_keyvault = SpecialAgent(
topic = Topic.NETWORKING,
name = "azure_keyvault",
title = Title("Azure Keyvault"),
parameter_form = _formspec_azure_keyvault_discovery,
)
rule_spec_agent_config_azure_keyvault_check = CheckParameters(
topic = Topic.NETWORKING,
name = "azure_keyvault",
title = Title("Azure Keyvault Check"),
parameter_form = _formspec_azure_keyvault_check,
condition = HostCondition(),
)
#check_plugin_juniper_trpz_cpu_util = CheckPlugin(
# name="juniper_trpz_cpu_util",
# service_name="CPU utilization",
# discovery_function=discovery_juniper_trpz_cpu_util,
# check_function=check_juniper_trpz_cpu_util,
# check_ruleset_name="cpu_utilization",
# check_default_parameters={"util": (80.0, 90.0)},
#)

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
# Copyright (C) 2025 Spearhead Systems SRL - License: GNU General Public License v2
from cmk.server_side_calls.v1 import noop_parser, SpecialAgentConfig, SpecialAgentCommand
def agent_azure_keyvault(params, hostname):
tenant = params["tenant"]
client = params["client"]
secret = params["secret"]
if type(secret) != str:
secret = secret.unsafe()
args = [tenant, client, secret]
for vault in params["vaults"]:
args.extend([vault.strip()])
yield SpecialAgentCommand(command_arguments=args)
special_agent_azure_keyvault = SpecialAgentConfig(
name = "azure_keyvault",
parameter_parser = noop_parser,
commands_function = agent_azure_keyvault,
)