Checkmk
Our AI policyAI

1. Introduction

With the password store, Checkmk can separate password management from their actual use. Prior to version 2.5.0, passwords stored there could be passed in plain text to special agents or active checks. In addition, a non-public API was available. This is now supplemented by an initial draft (v1_unstable) of a public API. This gives all extension developers the ability to have a special agent or active check read passwords directly from the store.

Incidentally, starting with Checkmk 2.5.0, the password store is also active in the background when you mark a password as Explicit. You can therefore work with the same programming interfaces without needing to know how the password in use is actually being managed.

Tip

Some of the programming interfaces presented here are marked as unstable at the present. We are currently planning to release the programming interfaces in Checkmk 3.0.0 as stable. This will require expanding the range of available functions. Minor changes to ensure compatibility may also be necessary for some APIs. You can expect a largely seamless transition to the stable version, but testing will still be necessary.

1.1. Scope of the examples shown

In this article, you will learn how to use secrets stored in the Password Store through two examples:

  • Ideally, you are developing your own special agents or active checks for which the performance of Python 3 is sufficient and that run under Checkmk starting with version 2.5.0. In this case, use the programming interfaces defined in cmk.password_store.v1_unstable in the special agent or active check. These interfaces are used to pass a reference to the password store and the ID of the password to be looked up.

  • In some cases, it is not possible to use Python 3. Or a special agent or active check must be executable under other monitoring systems or older versions of Checkmk. Or, an active check already exists and you simply need to create an invocation configuration for running it. In such cases, you can pass the password in plain text as a command-line argument. Additional measures may be necessary here to prevent the password from being read from the process list.

For illustrative purposes, both examples use a simple local check that outputs the passed password in the service description. The local check has the advantage that you do not need to write another check plug-in. Both examples thus require only three files.

We will not provide a detailed description in this article of how and after which customizations Checkmk services must be restarted. Please refer to the article on developing special agents for this information.

2. Secure handover of references

In case your special agent or active check only is required to operate under Checkmk (2.5.0 or higher), it is possible to securely hand over a reference to an object in the password store. In that case, the programming interfaces defined at cmk.password_store.v1_unstable are available to your program. With the reference to the object in the password store, your program can then retrieve the password itself.

In this example, we show a basic special agent that requires three sample files. If you want to reproduce the example, first create three folders:

OMD[mysite]:~$ mkdir -p ~/local/lib/python3/cmk_addons/plugins/hellopassword/libexec
OMD[mysite]:~$ mkdir -p ~/local/lib/python3/cmk_addons/plugins/hellopassword/rulesets
OMD[mysite]:~$ mkdir -p ~/local/lib/python3/cmk_addons/plugins/hellopassword/server_side_calls
Copy command(s) to clipboard
Successfully copied command(s) to clipboard!
Write access to clipboard has been denied!

2.1. The special agent

In the special agent, you import the following three items:

~/local/lib/python3/cmk_addons/plugins/hellopassword/libexec/agent_hellopassword
#!/usr/bin/env python3
# Shebang needed to find the interpreter!

import argparse
from cmk.password_store.v1_unstable import parser_add_secret_option, resolve_secret_option, Secret

SECRETOPT = "secret"

parser = argparse.ArgumentParser()
parser_add_secret_option(
    parser,
    long=f"--{SECRETOPT}",
    help="Specify the password to use.",
    required=True
)
args = parser.parse_args()

secret = resolve_secret_option(args, SECRETOPT)
print('<<<local>>>')
print('0 "Hello password" - The password you passed: ' + secret.reveal())
Copy file content to clipboard
Successfully copied file content to clipboard!
Write access to clipboard has been denied!

First, you create the parser for command-line arguments. Use parser_add_secret_option to add the Checkmk-specific extension for passing the reference to the password store. The key point: This creates two possible arguments—not only the expected one (here, --secret for handing over a password), but also a second one (--secret-id) for passing the reference.

Tip

For the following two tests, it is important that you have switched to the site user using omd su mysite. This is the only way to ensure that the execution environment matches the one under which the program will later be run by Checkmk.

The command-line invocation displays the two options that were created, --secret and --secret-id:

OMD[mysite]:~$ ~/local/lib/python3/cmk_addons/plugins/hellopassword/libexec/agent_hellopassword --help
usage: agent_hellopassword [-h] (--secret SECRET | --secret-id SECRET_ID)

options:
  -h, --help            show this help message and exit
  --secret SECRET       Specify the password to use.
  --secret-id SECRET_ID
                        Same as "--secret", but containing the reference to the password store rather than the actual secret.
Copy command(s) to clipboard
Successfully copied command(s) to clipboard!
Write access to clipboard has been denied!

For command-line tests, use the --secret option and pass the password in plain text:

OMD[mysite]:~$ ~/local/lib/python3/cmk_addons/plugins/hellopassword/libexec/agent_hellopassword --secret 7op53cre7
<<<local>>>
0 "Hello password" - The password you passed: 7op53cre7
Copy command(s) to clipboard
Successfully copied command(s) to clipboard!
Write access to clipboard has been denied!

In the next two sections, we’ll demonstrate how to pass references.

2.2. Form and rules for configuration

Via cmk.rulesets.v1.form_specs and link: cmk.rulesets.v1.rule_specs you can define the form visible in the setup and the corresponding rule configuration. After you have saved this file and restarted Checkmk, you can configure the rule for Hello password! with exactly one field: either a password stored in the Password Store or an explicitly specified password. For the purposes of this article, the distinction is irrelevant; the method of passing the value, which will be shown later, is always the same.

~/local/lib/python3/cmk_addons/plugins/hellopassword/rulesets/special_agent.py
#!/usr/bin/env python3
# Shebang needed only for editors

from cmk.rulesets.v1.form_specs import Dictionary, DictElement, Password, migrate_to_password
from cmk.rulesets.v1.rule_specs import SpecialAgent, Topic, Help, Title

def _formspec():
    return Dictionary(
        title=Title("Hello password!"),
        help_text=Help("This rule is to demonstrate accessing the password store from a special agent."),
        elements={
            "password": DictElement(
                required=True,
                parameter_form=Password(
                    title=Title("Password for this user"),
                ),
            ),
        }
    )

rule_spec_hellopassword = SpecialAgent(
    topic=Topic.GENERAL,
    name="hellopassword",
    title=Title("Hello password!"),
    parameter_form=_formspec
)
Copy file content to clipboard
Successfully copied file content to clipboard!
Write access to clipboard has been denied!

For further testing, you should create a separate host to which you assign only the Hello password! special agent and nothing else. Throughout the rest of this article, the name testhost will be used for this host.

2.3. Invocation configuration

The invocation configuration brings everything together. When generating the command-line parameters, --secret-id is used. The parameter params['password'] is implicitly converted to a reference to the password store:

~/local/lib/python3/cmk_addons/plugins/hellopassword/server_side_calls/special_agent.py
#!/usr/bin/env python3
# Shebang needed only for editors

from cmk.server_side_calls.v1 import noop_parser, SpecialAgentConfig, SpecialAgentCommand

def _agent_arguments(params, host_config):
    yield SpecialAgentCommand(command_arguments=[ "--secret-id", params['password'] ])

special_agent_hellopassword = SpecialAgentConfig(
    name="hellopassword",
    parameter_parser=noop_parser,
    commands_function=_agent_arguments
)
Copy file content to clipboard
Successfully copied file content to clipboard!
Write access to clipboard has been denied!

If you want to see how the reference is passed, just try running cmk -v -D testhost:

OMD[mysite]:~$ cmk -v -D testhost

testhost
Addresses:              No IP
Tags:                   [address_family:no-ip], [agent:special-agents], [criticality:prod], [networking:lan], [piggyback:auto-piggyback], [site:mysite], [snmp_ds:no-snmp], [tcp:tcp]
Labels:                 [cmk/site:mysite]
Host groups:            check_mk
Contact groups:         all
Agent mode:             No Checkmk agent, all configured special agents
Type of agent:
  Program: /omd/sites/mysite/local/lib/python3/cmk_addons/plugins/hellopassword/libexec/agent_hellopassword \
           --secret-id uuid37481a65-579f-4779-ba50-f303decafbad:/omd/sites/mysite/var/check_mk/passwords_merged
  Process piggyback data
Services:
  checktype item           params description    groups
  --------- -------------- ------ -------------- ------
  local     Hello password {}     Hello password
Copy command(s) to clipboard
Successfully copied command(s) to clipboard!
Write access to clipboard has been denied!

In the highlighted command line, you can see the reference separated by a colon. The first parameter is the UUID of the password to be retrieved; the second is the path to the password store to be used. Finally, when you view the service details for the Hello password service on your host testhost, you will see the password stored in the password store and revealed using secret.reveal().

3. Insecure handover of passwords

Choose this method only if, for example, you need to support other monitoring systems or older versions of Checkmk.

Important

Passwords handed over in plain text are visible in the process table! On Linux, any program can use the function setproctitle() from libbsd to remove passwords from the process name. Wrappers for this function exist for virtually all programming languages. However: Even if you use setproctitle(), the password is visible for a brief moment between the program’s startup and the successful call to setproctitle().

In this example, we’ll also demonstrate a minimal special agent that requires three sample files. If you want to reproduce the example, first create three folders:

OMD[mysite]:~$ mkdir -p ~/local/lib/python3/cmk_addons/plugins/hellopassword_insecure/libexec
OMD[mysite]:~$ mkdir -p ~/local/lib/python3/cmk_addons/plugins/hellopassword_insecure/rulesets
OMD[mysite]:~$ mkdir -p ~/local/lib/python3/cmk_addons/plugins/hellopassword_insecure/server_side_calls
Copy command(s) to clipboard
Successfully copied command(s) to clipboard!
Write access to clipboard has been denied!

3.1. Special agent

For this example, we’ve prepared a special agent as a simple shell script. The agent simply displays all of the command-line arguments passed to it:

~/local/lib/python3/cmk_addons/plugins/hellopassword_insecure/libexec/agent_hellopassword_insecure
#!/bin/bash

echo '<<<local>>>'
echo '0 "Hello password insecure" - You called me with: '"$@"
Copy command(s) to clipboard
Successfully copied command(s) to clipboard!
Write access to clipboard has been denied!

3.2. Form and rules for configuration

The form and the rules are the same as in the example above, except for the changed name of the plug-in family:

~/local/lib/python3/cmk_addons/plugins/hellopassword_insecure/rulesets/special_agent.py
#!/usr/bin/env python3
# Shebang needed only for editors

from cmk.rulesets.v1.form_specs import Dictionary, DictElement, Password, migrate_to_password
from cmk.rulesets.v1.rule_specs import SpecialAgent, Topic, Help, Title

def _formspec():
    return Dictionary(
        title=Title("Hello password (insecure)!"),
        help_text=Help("This rule is to demonstrate insecurely accessing the password store from a special agent."),
        elements={
            "password": DictElement(
                required=True,
                parameter_form=Password(
                    title=Title("Password for this user"),
                    migrate=migrate_to_password,
                ),
            ),
        }
    )

rule_spec_hellopassword_insecure = SpecialAgent(
    topic=Topic.GENERAL,
    name="hellopassword_insecure",
    title=Title("Hello password (insecure)!"),
    parameter_form=_formspec
)
Copy file content to clipboard
Successfully copied file content to clipboard!
Write access to clipboard has been denied!

3.3. Invocation configuration

The invocation configuration differs from the example shown above in a few important details. By convention, when generating the command-line parameters, --secret (or --password, in any case without an appended id) is used. The unsafe() method of the Secret object in (params['password'].unsafe()) now ensures that the password is read in plain text for the program invocation:

~/local/lib/python3/cmk_addons/plugins/hellopassword_insecure/server_side_calls/special_agent.py
#!/usr/bin/env python3
# Shebang needed only for editors

from cmk.server_side_calls.v1 import noop_parser, SpecialAgentConfig, SpecialAgentCommand

def _agent_arguments(params, host_config):
    yield SpecialAgentCommand(command_arguments=[ "--secret", params['password'].unsafe() ])

special_agent_hellopassword_insecure = SpecialAgentConfig(
    name="hellopassword_insecure",
    parameter_parser=noop_parser,
    commands_function=_agent_arguments
)
Copy file content to clipboard
Successfully copied file content to clipboard!
Write access to clipboard has been denied!

In the output of cmk -v -D testhost, Checkmk masks the password passed in plain text:

OMD[mysite]:~$ cmk -v -D testhost

testhost
Addresses:              No IP
Tags:                   [address_family:no-ip], [agent:special-agents], [criticality:prod], [networking:lan], [piggyback:auto-piggyback], [site:mysite], [snmp_ds:no-snmp], [tcp:tcp]
Labels:                 [cmk/site:mysite]
Host groups:            check_mk
Contact groups:         all
Agent mode:             No Checkmk agent, all configured special agents
Type of agent:
  Program: /omd/sites/mysite/local/lib/python3/cmk_addons/plugins/hellopassword_insecure/libexec/agent_hellopassword_insecure
           --secret '****'
  Process piggyback data
Services:
  checktype item                    params description             groups
  --------- ----------------------- ------ ----------------------- ------
  local     Hello password insecure {}     Hello password insecure
Copy command(s) to clipboard
Successfully copied command(s) to clipboard!
Write access to clipboard has been denied!

If you are using an active check from a third party (for example, from the Monitoring Plugins Collection), you should verify whether the check uses setproctitle(). For active checks or special agents that were developed for Checkmk prior to 2.5.0, and which are implemented in Python, it is often worth converting them to the secure method described above. If neither of these options is possible, ensure that only a small group of people can view the process list and that intercepted passwords cannot be abused.


Last modified: Mon, 10 Aug 2026 12:56:53 GMT via commit ce5e0613c
On this page