Cmk.base.plugins.bakery.bakery_api.v1.password_store does not match Password() valuespec

Hi @moritz ,

cmk.base.plugins.bakery.bakery_api.v1 has a password_store module, re-imported from cmk.utils.

This has a method extract which does not seem to be compatible with the new valuespec Password as it only gets an ID of type PasswordId.

But Password now generates a Tuple like ('cmk_postprocessed', 'explicit_password', ('uuiddc646119-6a96-432c-8d9c-7af3e479a9dc', 'password')).

What should we use in a bakery plugin when the ruleset has a Password?

1 Like

Yeah, that’s ugly. But you can use the generated id (uuiddc64...) to extract it from the password store. It does not matter anymore, whether the user chose “explicit” or “stored” – it will be in the store anyway. You can (and should) use password_store.lookup_for_bakery for now.

For a v2 of the bakery API I intend to do something similar (and yet the contrary) of what we do in the server_side_calls API: The bakery plugins should get a dedicated object, that does contain the actual secret. For bakery plugins we will always need access to it – no need to make the plugin developers look it up themselves. I intend to replace the ugly tuple you described by something like this:

class Secret(NamedTuple):
    # it seems that NamedTuple is the most reasonable way to create a pydantic compatible class
    # without adding a dependency on pydantic
    """Represents a configured secret to the bakery plugin

    This class aims to reduce the chances of accidentally exposing the secret in crash reports and log messages.
    However, a bakery plug-in produces configuration files that are deployed to the target system.
    Therefor the plugin needs access to the actual secret.
    As a result, we cannot guarantee that bakery plugins will not expose the secret in any way:

    Example:

        # this is passed by the backend to the bakery plugin
        >>> s = Secret("s3cr3t")

        >>> print(f"This is the secret as string: {s}")
        This is the secret as string: 4e738ca5563c06cfd0018299933d58db1dd8bf97f6973dc99bf6cdc64b5550bd

        >>> print(f"This is the secrets `repr`: {s!r}")
        This is the secrets `repr`: Secret('4e738ca5563c06cfd0018299933d58db1dd8bf97f6973dc99bf6cdc64b5550bd')

        >>> print(f"But we can see the actual value: {s.revealed!r}")
        But we can see the actual value: 's3cr3t'

    """

    revealed: str

    def _hash(self) -> str:
        return hashlib.sha256(self.revealed.encode("utf-8")).hexdigest()

    def __str__(self) -> str:
        return self._hash()

    def __repr__(self) -> str:
        """Mask the actual value of the secret

        This deliberately breaks the semantics of the `repr` function.
        """
        # The backend uses the `repr` function (pprint) to create a hash of the secret,
        # so make sure to not return something constant here.
        return f"Secret('{self._hash()}')"

What do you think?

1 Like

There is no method of this name in 2.3.0p34.

I have created two helper methods:

def _lookup_for_bakery(pw_id: str) -> str:
    return password_store.lookup(password_store.password_store_path(), pw_id)

def _get_password(v):
    if isinstance(v, tuple):
        if v[0] == "cmk_postprocessed":
            if v[1] == "explicit_password":
                return v[2][1]
            if v[1] == "stored_password":
                return _lookup_for_bakery(v[2][0])
    return None

IMHO this forcing of the new API v2 on extension developers was not a good idea when obviously not much of the internal code has been migrated.

:frowning: Oh. Too bad I didn’t backport this into 2.3. Would it help you if I did, or is too late anyway?

The question here is: Do you expect the bakery to use the pending configuration, or the activated one. We decided to use the activated one in lookup_for_bakery in 2.4 – so if you want to be consitent with that you should use password_store.core_password_store_path(password_store.LATEST_CONFIG) (not tested).

Why is there a difference?

For example: If a user creates a new rule (or, maybe even more surprising) changes an entry in the password store, but they did not yet activate the changes – would expect the change to be reflected in a newly baked agent package?
I don’t think this question has an obvious answer, but bakery plugins should behave consistently here.

In the past any changes to agent rules immediately changed the bakery output. No need for activation.

Yes. On the other hand, the general idea is that fiddling with the configuration will not break the running monitoring as long as changes are not activated.
But I understand that you are in favor of using the pending config?

Yes, as this has been the behaviour since the start of Checkmk.