A :logger primary filter that keeps a %Req.Request{} out of crash reports.
Why this exists
kubereq 0.4.5 changed how an exec/log websocket is established: its Req
adapter answers a synthetic 101 and casts the real request to the
connection process, which then performs the upgrade. When that upgrade is
rejected — a deleted Pod (404), a wrong container name (400), an unsupported
subprotocol (403) — or the socket fails, the connection process stops
abnormally, and OTP's crash report includes its last message: the cast,
carrying the whole %Req.Request{}.
That struct holds the kubeconfig. Measured against a live cluster:
- with a certificate kubeconfig,
:connect_optionscarriescert: <<48, 130, …>>— client-certificate DER, in a ~2 KB:errorline; - with a token kubeconfig — the in-cluster ServiceAccount posture, i.e.
production —
Req'sInspectimplementation redacts theauthorizationheader, butoptions.kubeconfig.current_user["token"]is printed in full.
A failed exec upgrade is a routine event: a Pod that was reaped mid-session
produces one. So without this filter a cluster credential reaches the log on an
ordinary day, which is precisely the leak
CrowdControl.Backend.Kubernetes.API's exception_reason/1 was written to close
for the return path.
What it does, and does not do
It redacts fields; it never drops an event. The reason, the process name and
the stacktrace all survive, so a crash is still diagnosable — only the request
term, the process state and the client info are replaced with
:redacted_by_crowd_control.
It is deliberately narrow: it fires only for a crash report that actually
carries a %Req.Request{} (or the Kubereq.Connect state), found by a
depth-bounded walk. Any other library's crash reports pass through untouched.
Opting out
config :crowd_control, redact_logs: falseSet that if you install your own filter, or if you would rather have the raw reports and accept what they contain.
Summary
Functions
The filter itself. Returns the event, possibly with fields redacted.
Installs the filter, unless config :crowd_control, redact_logs: false.
Functions
@spec filter(:logger.log_event(), term()) :: :logger.log_event()
The filter itself. Returns the event, possibly with fields redacted.
Never returns :stop: suppressing a crash report would trade a credential leak
for an invisible failure, which is a worse bargain.
@spec install() :: :ok
Installs the filter, unless config :crowd_control, redact_logs: false.
Idempotent: adding a filter under a name that already exists is a no-op, so a release that restarts the application does not accumulate filters.