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] [Assigned] (CAMEL-25518) camel-hashicorp-vault - secret refresh never detects updates of secrets outside the "secret" engine, nor updates made before its first check

     [ https://issues.apache.org/jira/browse/CAMEL-25518?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

shashank reassigned CAMEL-25518:
--------------------------------

    Assignee: shashank

> 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
>            Assignee: shashank
>            Priority: Major
>
> 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)