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)

Reply via email to