Repository navigation
Conversation
When a label patch fails, Notify queues it for retry. A later successful patch for the same label did not remove the queued one, so the 5-second retry loop re-sent the older value and overwrote the newer state. A leader that loses and quickly regains leadership could be left labeled vault-active=false. The client also kept the original Authorization header when retrying after a 401/403, even after reloading a rotated token from disk, so the retry always failed the same way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thank you for your submission! We require that all contributors sign our Contributor License Agreement ("CLA") before we can accept the contribution. Read and sign the agreement Learn more about why HashiCorp requires a CLA and what the CLA includes Have you signed the CLA already but the status is still pending? Recheck it. |
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.
Summary
Two bugs in Kubernetes service registration can leave the active node labeled
vault-active=false. A Service that selects onvault-active=truethen has no endpoints.1. A successful patch does not replace an older failed patch for the same label.
Notify(patch) if PatchPod(patch) fails patchesToRetry[patch.Path] = patch + return + delete(patchesToRetry, patch.Path)Before this change, the sequence
Notify(active=false)(fails), thenNotify(active=true)(succeeds) leftfalsequeued. The 5-secondperiodicUpdateStateloop then sentfalseand overwrote the correct label. The comment onpatchesToRetryalready says it should hold only "the last state we were aware of".2. A retry after 401/403 sends the old token.
getCheckRetryreloads the token file on 401/403 and retries. Butdo()sets theAuthorizationheader once, beforeclient.Do, so the retry still sends the old token and fails the same way.retryablehttp.Client{ CheckRetry: c.getCheckRetry(req), // reloads c.config on 401/403 + PrepareRetry: set Authorization from c.config.BearerToken }How we hit this
Kubernetes service registration reads the service account token once at startup. It uses the token only when HA state changes. With bound service account tokens, that token expires (EKS caps it at 24h). As a result, a long-running node's first label update after a leadership change gets a 401.
In our case, a storage failover made the active node lose leadership and regain it about 3 seconds later. The API server audit log showed:
The active node stayed labeled
falseuntil we fixed it by hand. Either fix alone breaks this chain. Fix 1 also covers other transient failures, such as 5xx responses or network errors during a fast leadership flap.Related: #32148 (a different failure mode with the same symptom: no pod labeled active).
Evidence
New test
TestRetryHandlerNotifySupersedesQueuedPatch:retry_handler_test.go:485: expected "true" but received "false"After:
okToken refresh on retry (a local check against a test server that returns 401 unless it gets the new token; not committed):
[Bearer old Bearer old],giving up after 2 attempt(s): ... resp statuscode: 401After: headers sent
[Bearer old Bearer new], successgo test -race ./serviceregistration/kubernetes/...passes.Merge Danger
Door: two-way
Stateless client-side change. A revert restores the old behavior.
Blast Radius: narrow
Only Kubernetes service registration label patching. A successful
Notifynow also clears the queued retry for the same label. Retries for other labels are not affected. Retries after 401/403 now send the reloaded token. Requests that did not fail are unchanged.🤖 Generated with Claude Code