watch credential secrets and re-issue when they disappear - #5
Open
vramperez wants to merge 1 commit into
Open
Conversation
The reconciler's fast path skipped any request whose Ready condition was True and whose nextRenewalTime was still in the future, consulting only the status and never the storage backend. The controller also watched nothing but the VerifiableCredentialRequest itself. A credential Secret deleted out-of-band therefore stayed missing until the next scheduled renewal -- typically hours or days -- leaving the consuming service without a credential for that whole window. Watch the credential Secrets the controller owns, and make the renewal gate consult the CredentialStore before skipping. Retrieve now reports an absent credential as credentialstore.ErrNotFound, which the reconciler treats as "re-issue now" regardless of the renewal schedule. Mapping the existing "Secret has no credential key" branch onto the same sentinel makes an emptied Secret self-heal like a deleted one. Any other error is assumed to mean the credential is present: a successful reconciliation resets the workqueue rate limiter, so treating transient backend failures as credential loss would let a flaky backend drive an unthrottled re-issuance storm against the issuer. The watch uses Owns, since credential Secrets already carry an owner reference with Controller: true, and watch on Secrets was already granted. A predicate drops the operator's own writes, which would otherwise enqueue a redundant reconciliation after every issuance plus one per managed Secret on each informer resync. A restore reuses the renewal accounting path, so it increments renewalCount and credentials_renewed_total; the StoredCredentialMissing warning event is what distinguishes it from a scheduled renewal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| // credential is no longer present in the storage backend (for example, | ||
| // the target Secret was deleted or emptied out-of-band), which triggers | ||
| // an immediate re-issuance. | ||
| ReasonStoredCredentialMissing = "StoredCredentialMissing" |
Mortega5
approved these changes
Aug 7, 2026
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.
The reconciler's fast path skipped any request whose Ready condition was True and whose nextRenewalTime was still in the future, consulting only the status and never the storage backend. The controller also watched nothing but the VerifiableCredentialRequest itself. A credential Secret deleted out-of-band therefore stayed missing until the next scheduled renewal -- typically hours or days -- leaving the consuming service without a credential for that whole window.
Watch the credential Secrets the controller owns, and make the renewal gate consult the CredentialStore before skipping.
Retrieve now reports an absent credential as credentialstore.ErrNotFound, which the reconciler treats as "re-issue now" regardless of the renewal schedule. Mapping the existing "Secret has no credential key" branch onto the same sentinel makes an emptied Secret self-heal like a deleted one. Any other error is assumed to mean the credential is present: a successful reconciliation resets the workqueue rate limiter, so treating transient backend failures as credential loss would let a flaky backend drive an unthrottled re-issuance storm against the issuer.
The watch uses Owns, since credential Secrets already carry an owner reference with Controller: true, and watch on Secrets was already granted. A predicate drops the operator's own writes, which would otherwise enqueue a redundant reconciliation after every issuance plus one per managed Secret on each informer resync.
A restore reuses the renewal accounting path, so it increments renewalCount and credentials_renewed_total; the StoredCredentialMissing warning event is what distinguishes it from a scheduled renewal.