[9.4](backport #7571) fix: gracefully handle missing secrets in policy monitor - #7575
[9.4](backport #7571) fix: gracefully handle missing secrets in policy monitor#7575mergify[bot] wants to merge 3 commits into
Conversation
* fix: gracefully handle missing secrets in policy monitor
A 404 from GET /_fleet/secret/{id} was treated as a fatal error,
causing the policy monitor to abort and fleet-server to crash-loop —
taking all agents offline when a single integration credential was
missing from the Fleet secrets store.
Add ErrSecretNotFound sentinel to ExtendedAPI.Read so callers can
distinguish "this secret doesn't exist" from network/auth errors.
Change ReadSecrets to log a warning and skip missing secrets rather
than aborting, so the policy loads without the missing value and
only the affected integration degrades.
Closes #7536
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Update changelog/fragments/1786053515-graceful-missing-secrets.yaml
Co-authored-by: Michel Losier <mikelosier@gmail.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Michel Losier <mikelosier@gmail.com>
(cherry picked from commit 5ece0ba)
# Conflicts:
# internal/pkg/bulk/secret.go
|
Cherry-pick of 5ece0ba has failed: To fix up this pull request, you can check it out locally. See documentation: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally |
This comment has been minimized.
This comment has been minimized.
Cherry-pick left unresolved conflict markers in secret.go for the
imports ("errors", "fmt", "io") and the status-code check blocks.
Take both incoming additions as intended by the original fix.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The >= 400 check was introduced on main in #7416 but never backported to these branches. The cherry-pick dragged it in as a side-effect. Remove it so non-404 errors fall through as they did before, keeping the backport minimal and matching the intent of #7571. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TL;DRAll four Buildkite unit-test jobs are failing due to a deterministic unit-test regression: Remediation
Investigation detailsRoot CauseCommit
The same PR adds a test that expects HTTP 500 to return an error:
With the current code, a 500 response body like Evidence
No matching Verification
Follow-upIf you want strict backport minimalism, drop/adjust only the new server-error assertion; if you want parity with mainline safety behavior, restore What is this? | From workflow: PR Buildkite Detective Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not. |
|
This pull request has not been merged yet. Could you please review and merge it @ycombinator? 🙏 |
What is the problem this PR solves?
Fleet Server crash-loops when any secret referenced in an agent policy's
secret_referencescannot be found in the Fleet secrets store. A single missing secret — from a deleted or orphaned integration credential — causes the entire policy monitor to abort with:Fleet Server then restarts, re-reads the same stale policy document from the policy monitor (the checkpoint hasn't advanced), encounters the same 404, and crashes again — indefinitely. Every agent on that fleet-server instance goes offline for the duration.
This is a disproportionate blast radius: one deleted integration credential (unrelated to fleet-server's own connectivity) can take the entire Fleet Server offline.
The root causes that produce missing secrets are tracked in Kibana (elastic/kibana#282911 and elastic/kibana#282912) and in fleet-server (#7533, #7534). This PR is a defense-in-depth fix: even after those root causes are resolved, fleet-server should not treat a single missing package-policy credential as a reason to crash-loop and take all agents offline.
How does this PR solve the problem?
Two changes:
bulk/secret.go—ExtendedAPI.Read: Returns a typedErrSecretNotFoundsentinel when the Fleet secrets API responds with 404. This lets callers distinguish "this secret document doesn't exist" from network/auth failures (403, 500, etc.), which should still be fatal.bulk/engine.go—ReadSecrets: WhenReadSecretreturnsErrSecretNotFound, logs a warning with the secret ID and skips it (continues the loop) rather than aborting. The returned map contains only the secrets that were successfully fetched.With this change, a missing secret causes the policy to load without that secret value — the raw
$co.elastic.secret{id}placeholder remains unsubstituted in the affected integration's config. That integration's credentials won't resolve (it will fail to authenticate), but fleet-server itself stays up and continues serving all other agents.Callers that need hard failure for missing secrets (e.g. output API key resolution, where an empty key would silently break agent→ES connectivity) can check whether the expected ID is present in the returned map — as the second commit in #7416 already does.
How to test this PR locally
DELETE /_fleet/secret/<id>WARN secret not found; policy will load without it secret_id=<id>$co.elastic.secret{id}placeholder rather than the secret valueDesign Checklist
ReadSecretsindependently per policy load; skipping is per-request with no shared state.)Checklist
./changelog/fragmentsusing the changelog toolRelated issues
agentPolicyService.delete()can leave orphaned.fleet-policiesdocuments when the cleanup call after package-policy deletion fails silentlydeleteSecretsIfNotReferencedonly checks live package-policy saved objects, not.fleet-policies, so secrets are deleted even when an orphaned policy document still references them>= 400check inExtendedAPI.Readwas introduced in Store output API key secrets in .fleet-secrets instead of .fleet-agents #7416. That PR's own second commit described the original tolerant design —ReadSecretswas not expected to fail on a missing secret; hard failure for the output API key was added at the caller level. This PR restores that layered design by making 404 non-fatal inReadSecretswhile preserving fatal behavior for other 4xx/5xx responses.This is an automatic backport of pull request fix: gracefully handle missing secrets in policy monitor #7571 done by Mergify.