Cache Vault KV version by mount path to reduce preflight calls (CONCOURSE_VAULT_ENABLE_KV_MOUNT_CACHE)#9530
Conversation
Signed-off-by: IvanChalukov <ichalukov@gmail.com>
Signed-off-by: IvanChalukov <ichalukov@gmail.com>
…sions Signed-off-by: IvanChalukov <ichalukov@gmail.com>
These tests validate that enabling the KV mount cache does not break end-to-end credential resolution for both KV v1 and v2 mounts. Signed-off-by: IvanChalukov <ichalukov@gmail.com>
Signed-off-by: IvanChalukov <ichalukov@gmail.com>
There was a problem hiding this comment.
Looks good to me, I tested by configuring the compose yaml with an internal Vault we use trough approle auth. I used debug logs as I do not have server side access to the Vault and the web container doesn't have ngrep, wireshark etc. and the cache is in memory. As I already spoke to you what is TBD from my perspective is the docs, helm and bosh packaging stuff. Logs from testing in collapsed details section.
Details
Logs enabled:
docker logs fork-concourse-ivan-web-1 | grep kv-mount-cache
{"timestamp":"2026-04-20T08:30:12.879820721Z","level":"debug","source":"atc","message":"atc.credential-manager.kv-mount-cache-miss","data":{"name":"vault","secret-path":"test/test/concourse/test-vault/test-secret/","session":"7"}}
{"timestamp":"2026-04-20T08:30:13.005661930Z","level":"debug","source":"atc","message":"atc.credential-manager.kv-mount-cache-fetched-from-vault","data":{"is-v2":true,"mount-path":"test/","name":"vault","secret-path":"test/test/concourse/test-vault/test-secret/","session":"7"}}
{"timestamp":"2026-04-20T08:30:13.005750680Z","level":"debug","source":"atc","message":"atc.credential-manager.kv-mount-cache-stored","data":{"is-v2":true,"mount-path":"test/","name":"vault","session":"7"}}
{"timestamp":"2026-04-20T08:30:13.057563763Z","level":"debug","source":"atc","message":"atc.credential-manager.kv-mount-cache-hit","data":{"is-v2":true,"mount-path":"test/","name":"vault","secret-path":"test/test/concourse/test-secret/","session":"7"}}
{"timestamp":"2026-04-20T08:32:22.410623961Z","level":"debug","source":"atc","message":"atc.credential-manager.kv-mount-cache-hit","data":{"is-v2":true,"mount-path":"test/","name":"vault","secret-path":"test/test/concourse/test-vault/test-secret/","session":"7"}}
{"timestamp":"2026-04-20T08:32:22.694515545Z","level":"debug","source":"atc","message":"atc.credential-manager.kv-mount-cache-hit","data":{"is-v2":true,"mount-path":"test/","name":"vault","secret-path":"test/test/concourse/test-secret/","session":"7"}}
Logs disabled:
docker logs fork-concourse-ivan-web-1 | grep kv-mount-cache
{"timestamp":"2026-04-20T09:36:32.028043715Z","level":"debug","source":"atc","message":"atc.credential-manager.kv-mount-cache-disabled","data":{"name":"vault","secret-path":"test/test/concourse/test-vault/test-secret/","session":"7"}}
{"timestamp":"2026-04-20T09:36:32.324927382Z","level":"debug","source":"atc","message":"atc.credential-manager.kv-mount-cache-disabled","data":{"name":"vault","secret-path":"test/test/concourse/test-secret/","session":"7"}}
{"timestamp":"2026-04-20T09:38:11.160152428Z","level":"debug","source":"atc","message":"atc.credential-manager.kv-mount-cache-disabled","data":{"name":"vault","secret-path":"test/test/concourse/test-vault/test-secret/","session":"7"}}
{"timestamp":"2026-04-20T09:38:11.547221345Z","level":"debug","source":"atc","message":"atc.credential-manager.kv-mount-cache-disabled","data":{"name":"vault","secret-path":"test/test/concourse/test-secret/","session":"7"}}
Edit: let me know if you need help/reviews in the packaging stuff as well.
Signed-off-by: Taylor Silva <dev@taydev.net>
Signed-off-by: Taylor Silva <dev@taydev.net>
Signed-off-by: Taylor Silva <dev@taydev.net>
These tests pass even when the cache is disabled. They don't validate that the cache has been hit. The way the cache is implemented, it falls back to doing the `isKVv2()` pre-flight request. So even if there was an error in the caching code, this test would not catch it because we would be falling back to doing the pre-flight request. Signed-off-by: Taylor Silva <dev@taydev.net>
There was a problem hiding this comment.
For these tests, why is the cache disabled for the v2 client and enabled for the v1 client?
| path "secret*" { | ||
| policy = "read" | ||
| } | ||
| `)).Run(t, "policy", "write", "concourse", "-") |
There was a problem hiding this comment.
nit: is this needed? A /secret mount doesn't appear to be used in the tests here.
There was a problem hiding this comment.
It is a leftover from testing, it should be deleted as you did. Thanks for that!
There was a problem hiding this comment.
I'm not sure integration tests are very useful here. I think these tests pass regardless if the KV cache is enabled or not.
Update: yup, they pass even when the cache is disabled.
Integration tests take longer, so I'm always a bit hesitant to add them. As-is, these tests don't error if the mount cache is not being used.
There was a problem hiding this comment.
Thanks for raising your concerns about the integration tests. I was unsure where the functionality should be validated and didn’t realize the tests would pass in both scenarios (enabled and disabled).
I’ll keep this in mind for future PRs.
|
I've gone ahead and removed the integration-level tests and added unit tests instead that fail if the cache is not hit on subsequent calls. Cleaned up the small nits I mentioned as well. I didn't make any other changes. Everything else LGTM. Feature works as expected. TY for working on this Ivan! |
CONCOURSE_VAULT_ENABLE_KV_MOUNT_CACHE)
|
@taylorsilva I've opened PRs for packaging stuff:
|
|
You da bestttt 🙏 👏 |
Changes proposed by this PR
closes #9514
This PR adds KV mount version caching for Vault so Concourse does not run mount preflight on every secret read.
What changed
Notes to reviewer
Enablement
var_sources: