You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "shashank (Jira)" <ji...@apache.org> on 2026/10/10 09:50:00 UTC

[jira] [Created] (CAMEL-25518) camel-hashicorp-vault - secret refresh never detects updates of secrets outside the "secret" engine, nor updates made before its first check

shashank created CAMEL-25518:
--------------------------------

             Summary: camel-hashicorp-vault - secret refresh never detects updates of secrets outside the "secret" engine, nor updates made before its first check
                 Key: CAMEL-25518
                 URL: https://issues.apache.org/jira/browse/CAMEL-25518
             Project: Camel
          Issue Type: Bug
          Components: camel-hashicorp-vault
            Reporter: shashank


The secret refresh added by CAMEL-22676 ({{camel.vault.hashicorp.refreshEnabled=true}}) polls {{<engine>/metadata/<secret>}} for every tracked secret. Besides the names listed in {{camel.vault.hashicorp.secrets}}, it tracks every secret resolved with the {{hashicorp:}} properties function; when that option is not set, the documentation says the task takes into account all the properties with a {{hashicorp:}} prefix.

1. {{HashicorpVaultPropertiesFunction.getSecretFromSource}} records only the key: {{secrets.add(key)}} (line 214 at main c578a42a776d), so {{hashicorp:kv:db#password}} is recorded as {{db}}. {{HashicorpVaultReloadTriggerTask.buildMetadataPath}} (lines 272-297) reads a name without an engine from the {{secret}} engine, so it reads {{secret/metadata/db}}, which does not exist; {{VaultTemplate.read}} returns null and the task skips it without a log. For a secret in any engine other than {{secret}} (for example {{kv}}), an update never triggers a reload unless the user also lists it as {{kv:db}} in {{camel.vault.hashicorp.secrets}}.
2. The first run of the task only records the version it reads (lines 212-215: "First time seeing this secret, just record the version"). The first run happens one refresh period after startup (60 s by default). If the secret is updated in that window, the new version becomes the baseline and the application keeps the value it resolved at startup until the secret changes again.

h3. Reproduction

New {{HashicorpVaultReloadTriggerTaskTest}} with a minimal in-process fake of the Vault KV v2 HTTP API (JDK {{HttpServer}}, no container): resolve {{hashicorp:kv:db#password}} (version 1), run the task, set version 2, run the task; and resolve {{hashicorp:secret:api#password}} (version 1), set version 2, run the task. On main:
{noformat}
rotationInNonDefaultEngineIsDetected: the refresh task must read the metadata of the engine the secret was resolved from, but read [secret/metadata/db, secret/metadata/db] ==> expected: <true> but was: <false>
rotationBeforeFirstCheckIsDetected: the application resolved version 1 but version 2 was not detected, updates: {} ==> expected: <false> but was: <true>
secretsAreTrackedWithTheirEngine: expected: <[api, kv:db]> but was: <[api, db]>
{noformat}

h3. Proposed fix

The properties function records the secret in the format of {{camel.vault.hashicorp.secrets}}: {{engine:secret}}, or only {{secret}} for the default {{secret}} engine (so the names of secrets in the {{secret}} engine do not change, and a resolved secret has the same name as when it is listed in the option, so it is not checked twice). It also remembers the version it read ({{data.metadata.version}} of the KV v2 response; not when a specific {{@version}} was requested). For a secret the task has not seen before, it starts from that version, so a newer version in Vault triggers a reload at the first check. {{getSecrets()}} and the task's updates now name secrets of other engines {{engine:secret}}; component docs and a 4.23 upgrade guide note updated. The recorded set and the new version map are concurrent collections, as the refresh task reads them from its own thread. camel-hashicorp-vault unit tests: 6, 0 failures (the ITs need a Vault container and were not run).

Found with a TLA+ model of startup resolution, rotations and the check runs (metadata read, version compare, reload): "after a complete check run with no update since it started, the application uses the current version of every secret" is violated for a {{kv}} secret relying on auto-detection (12 steps: resolve, two check runs around one update, no reload) and for an update before the first check (8 steps); it holds on main for the {{secret}} engine with updates after the first check, and with {{camel.vault.hashicorp.secrets=kv:db}}. With the fix it holds for two secrets in different engines with two updates at any time. Then confirmed with the real classes as above.

Workaround on affected versions: list every secret of a non-default engine as {{engine:secret}} in {{camel.vault.hashicorp.secrets}} (fixes 1, not 2).

Affected: 4.17.0 and later (camel-4.18.x and camel-4.22.x have the same code; camel-4.14.x has no secret refresh).

Duplicate check (2026-10-09): JIRA component camel-hashicorp-vault (7 issues, none about the refresh), text "HashicorpVaultReloadTriggerTask" (none), "hashicorp" with "refresh"/"reload"/"engine" (9; CAMEL-22676/22677 added the feature, CAMEL-24636 is the re-authentication SPI); GitHub pull requests "hashicorp refresh", "HashicorpVaultReloadTriggerTask": none; no open PR touches camel-hashicorp-vault.

_Filed with Claude Code on behalf of allthingssecurity._




--
This message was sent by Atlassian Jira
(v8.20.10#820010)