dependency: account for the HTTP Age header when timing lease re-renders - #2160
Draft
peteski22 wants to merge 4 commits into
Draft
dependency: account for the HTTP Age header when timing lease re-renders#2160peteski22 wants to merge 4 commits into
peteski22 wants to merge 4 commits into
Conversation
leaseCheckWait decides how long to sleep before re-rendering a non-renewable secret, using lease_duration alone. Behind a caching proxy the response reports the duration measured from issuance, and the HTTP Age header says how stale it is, so the lease has lease_duration - Age left, not lease_duration. Add an inert Age field to Secret so the behaviour can be pinned, and a failing test: a 100s lease returned with Age 90s has 10s left, but leaseCheckWait sleeps ~90s and wakes long after it has expired. The dependency package test binary needs consul and nomad on PATH (TestMain starts them), so this runs in CI; the arithmetic is deterministic because the package init pins VaultLeaseRenewalThreshold. Ref: hashicorp/vault#19684
leaseCheckWait sleeps for a fraction of the lease duration before re-rendering a non-renewable secret, measured from now. Behind a caching proxy the response has already been held for its Age, so that much of the wait has elapsed and the client would otherwise wake after the lease had expired. Subtract the Age from the computed sleep for lease-bearing responses, clamped at zero. This is a no-op when Age is zero, so responses served directly by Vault are unaffected.
Populate Secret.Age from the api response so leaseCheckWait can discount the time a response spent in a cache. The api gained this field in hashicorp/vault#32040. The replace directive is a temporary bridge to that change on an unreleased branch and must be dropped for a real api release before this can merge. Ref: hashicorp/vault#32040
peteski22
force-pushed
the
fix-lease-check-wait-cache-age
branch
from
July 22, 2026 12:29
cecd28b to
8d15c86
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
leaseCheckWaitdecides how long Consul Template sleeps before re-rendering a non-renewable Vault secret, usinglease_durationmeasured from now. Behind a caching proxy in front of Vault, the response has already been held for some time — reported in the HTTPAgeheader — so the lease haslease_duration - Ageleft, notlease_duration. Consul Template ignoredAge, so it slept for most of the original lease again and re-rendered only after the credential had already expired. This shows up most as a lease approaches itsmax_ttl, where the template keeps rendering a secret that is already dead.This change:
Agefield todependency.Secret, populated from the api response (which gains the field in api: account for the HTTP Age header when renewing leases through a cache vault#32040), andAgefrom the computed sleep inleaseCheckWait, clamped at zero.It is a no-op for responses served directly by Vault (
Ageis zero), so behaviour without a cache in front is unchanged.The first two commits are a failing test and its fix; the third wires the value through from the api response.
Warning
This is a draft and must not be merged yet. It depends on hashicorp/vault#32040, which adds
api.Secret.Age. Until that merges and a newgithub.com/hashicorp/vault/apiis released,go.modcarries a temporaryreplaceto an unreleased branch (marked// NOTE: TEMPORARY, DO NOT MERGE!). Before this can merge, that replace must be dropped and the api dependency bumped to the real release.The
dependencypackage's tests needconsulandnomadon$PATH(itsTestMainstarts them), so the new test runs in CI.Rationale
This is the client-side counterpart to hashicorp/vault#32040, which fixes
api.LifetimeWatcher— the mechanism Consul Template uses for renewable secrets. This change covers the non-renewable secret path, which has its own timing logic inleaseCheckWaitand is not touched by that fix.Canonical issue: hashicorp/vault#19684 (Vault Agent lease cache interferes with template refresh for dynamic secrets). Background: hashicorp/vault#19227, hashicorp/vault#16439.
PCI review checklist
I have documented a clear reason for, and description of, the change I am making.
If applicable, I've documented a plan to revert these changes if they require more than reverting the pull request.
If applicable, I've documented the impact of any changes to security controls.