Repository navigation
fix(k8saudit): stop the webhook from blocking on a full event queue - #1600
Merged
poiana merged 1 commit intoNov 3, 2026
Merged
Conversation
The webhook handler wrote 200 and then waited without a limit for room in the event queue, ignoring the request context. The response reaches the API server only when the handler returns, so with a full queue the API server cancelled the request after its 30-second timeout and sent the batch again, while the cancelled handler still queued its copy. Every batch was then processed at least twice, the queue never drained, and most audit events were lost until Falco was restarted, even after the load went down. The handler now answers 200 only after the batch is queued, waits for room in the queue for at most webhookEnqueueTimeout seconds (default 5) and then answers 429 without Retry-After, so that the API server retries the batch with the exponential back-off of its audit webhook. A batch whose request has been cancelled is not queued. Refused batches are logged separately for each reason, at most once in two enqueue timeouts and at least one second apart. Signed-off-by: suselz <suselz@mail.ru>
Contributor
|
Welcome @Suselz! It looks like this is your first PR to falcosecurity/plugins 🎉 |
Rules files suggestionsrulesComparing No changes detected |
Contributor
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: leogr, Suselz The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Contributor
|
LGTM label has been added. DetailsGit tree hash: 2d6a828658e1493a9b20d061b5a59055b47941fe |
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.
What type of PR is this?
/kind bug
Any specific area of the project related to this PR?
/area plugins
What this PR does / why we need it:
The webhook handler no longer waits without a limit for room in the event queue,
and it no longer queues a batch whose request the API server has already cancelled.
Without this, Falco stops seeing most audit events after the queue fills up once, until it is restarted.
Today the handler writes
200and then blocks onserverEvtChan <- b(50 batches) without watchingreq.Context().The status reaches the API server only when the handler returns.
With a full queue, the API server cancels the request after its 30-second timeout and sends the batch again,
while the cancelled handler still queues its copy.
Every batch is processed at least twice, so the queue never drains, even after the load goes down.
With this change, the handler:
200only after that;webhookEnqueueTimeoutseconds, then answers429withoutRetry-After;503and does not queue the batch when the request is cancelled while waiting, or when the server shuts down;at most once in two enqueue timeouts and at least one second apart.
Why
429withoutRetry-After:429or5xxresponsecarries
Retry-After(checkWait).With the header, it would resend the same batch within the same 30-second request timeout and keep the queue under pressure;
(
WithExponentialBackoff,DefaultRetryBackoffWithInitialDelay):five attempts with pauses of 10, 15, 22.5 and 33.75 seconds by default, each with up to 20% of jitter.
After the last attempt, the API server drops the batch and counts it in
apiserver_audit_error_total.New init config parameter
webhookEnqueueTimeout: the maximum time in seconds a webhook request waits for roomin the event queue before it is refused with
429. The default is5, well below the 30-second request timeoutof the audit webhook. A value of
0refuses a request at once when the queue is full.The parameter is described in the init schema and in the plugin README.
How it was tested:
go build ./...,go vet ./...andgo test ./...inplugins/k8sauditpass, also with-race -count=3for the new tests;pkg/k8saudit/webserver_test.gofail with thesource.goofmain:the request over a full queue hangs until the client gives up, and the cancelled request is still being handled after 5 seconds;
makeinplugins/k8sauditbuildslibk8saudit.so, andgolangci-lint run --new-from-rev=mainreports no issues in the change;webhookEnqueueTimeoutset, rejects a non-integer value through the init schema,answers
200to a webhook batch and triggers a rule fromk8s_audit_rules.yaml;200mCPU, the audit webhookwas overloaded for about 4 minutes. Without the change, events were not delivered after the load went down until Falco was restarted.
With the change, all test events sent after the overload were delivered in three runs,
and
apiserver_audit_error_totalstopped growing a few minutes after the overload.Which issue(s) this PR fixes:
Fixes #1599
Special notes for your reviewer:
The event parser goroutine of
OpenWebServerdoes not watch the instance context while it pushes events(
source.go#L388).In the tests that fill the queue, nothing reads the events, so the parser stays blocked on its output channel after
Close,and its goroutine leaks until the test binary exits. It holds no port and does not affect other tests.
This PR does not change the parser, since the leak does not affect the webhook behaviour fixed here.
A slot that frees up at the moment the request is cancelled can still take the batch.
This is no worse than a cancellation right after the batch is queued, which the handler cannot detect either.
I did not bump the plugin version or edit
CHANGELOG.md, since recent changes leave both to separate release PRs.Does this PR introduce a user-facing change?: