Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions docs/setup-robusta/configuration-secrets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,64 @@ You can now reference the environment variable elsewhere in your configuration u

This setup keeps sensitive values out of your Helm files and version control, while still allowing them to be dynamically injected at runtime.

You can also combine static text with placeholders (e.g. ``"Bearer {{ env.TOKEN }}"``)
or reference multiple environment variables in the same field
(e.g. ``"{{ env.USER }}:{{ env.PASSWORD }}"``).

.. note::

``{{ env.X }}`` substitution only happens inside Robusta's configuration
(``sinks``, ``globalConfig``, ``customPlaybooks``, ``playbookRepos``). The
environment variable still needs to actually exist inside the pod that reads
that config — see :ref:`Runner vs. HolmesGPT pods` below.

Injecting Many Keys at Once with ``additional_env_froms``
-----------------------------------------------------------

If you have a Secret (or ConfigMap) with multiple keys you want to expose to the
runner, ``runner.additional_env_froms`` is often less verbose than listing each
key under ``additional_env_vars``:

.. code-block:: yaml

runner:
additional_env_froms:
- secretRef:
name: my-robusta-secrets

Every key in ``my-robusta-secrets`` becomes an environment variable on the runner
pod (key name = env var name), which you can then reference with
``{{ env.KEY_NAME }}``.

.. _Runner vs. HolmesGPT pods:

Runner vs. HolmesGPT Pods
--------------------------------------------------

Robusta runs as multiple pods. An environment variable defined under ``runner.additional_env_vars``
is **only** available to the runner; one defined under ``holmes.additionalEnvVars`` is **only**
available to the HolmesGPT pod. If a value (e.g. an API key) is consumed by both, you must add
the env var to **both** blocks — they do not share environment.

A common pitfall: a secret referenced inside ``globalConfig`` is read by the runner, so it
needs to be in ``runner.additional_env_vars``. The same secret used by HolmesGPT must
**also** be added to ``holmes.additionalEnvVars``.

Secrets for HolmesGPT Add-Ons
--------------------------------------------------

The ``holmes.additionalEnvVars`` block only injects env vars into the main HolmesGPT pod.
HolmesGPT also ships several optional sub-deployments that have their own
``additionalEnvVars`` arrays:

- ``holmes.operator.additionalEnvVars`` — for the HolmesGPT operator
- ``holmes.mcpAddons.aws.additionalEnvVars`` — for the AWS MCP add-on
- ``holmes.mcpAddons.azure.additionalEnvVars`` — for the Azure MCP add-on

If you enable any of those add-ons and need to pass them a secret, add it under the
matching block — values placed only in ``holmes.additionalEnvVars`` will not reach
the add-on pods.

.. _Reading the Robusta UI Token from a secret in HolmesGPT:

Using an Existing Secret for the Robusta UI Token
Expand Down
17 changes: 12 additions & 5 deletions src/robusta/core/playbooks/playbook_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,23 @@
from pydantic.types import SecretStr


_ENV_PLACEHOLDER_RE = re.compile(r"{{\s*env\.([^}\s]+)\s*}}")


def get_env_replacement(value: str) -> Optional[str]:
env_values = re.findall(r"{{[ ]*env\.(.*)[ ]*}}", value)
if env_values:
env_var_value = os.environ.get(env_values[0].strip(), None)
if not _ENV_PLACEHOLDER_RE.search(value):
return None

def _sub(match: "re.Match[str]") -> str:
name = match.group(1).strip()
env_var_value = os.environ.get(name, None)
if not env_var_value:
msg = f"ENV var replacement {env_values[0]} does not exist for param: {value}"
msg = f"ENV var replacement {name} does not exist for param: {value}"
logging.error(msg)
raise Exception(msg)
return env_var_value
Comment thread
aantn marked this conversation as resolved.
return None

return _ENV_PLACEHOLDER_RE.sub(_sub, value)


def replace_env_vars_values(values: Dict) -> Dict:
Expand Down
Loading