Repository navigation
feat(traefik): legacy group, CRD secret redaction, detail renderers, audit checks - #1012
Merged
Merged
Conversation
…erers, audit checks Four independent improvements to Traefik support: 1. Warm-list the legacy traefik.containo.us CRD group alongside traefik.io so pre-v2.11 clusters get pre-warmed informers (resolution already worked for single-group clusters; this restores first-list latency parity). 2. Key-aware secret redaction for unstructured CRD specs sent to the LLM/MCP context. Previously only core Secrets and env values were redacted; an inline credential in a CRD spec passed through verbatim. Now spec/status string values are redacted when their key is a value-bearing credential name, or when the value matches a high-confidence pattern (token shapes, htpasswd hashes) — reference keys (secretName, secretRef, rootCAsSecrets) are deliberately preserved, and the broad base64 rule is not applied to arbitrary fields to avoid eating hashes/IDs. 3. Detail renderers for Middleware (+MiddlewareTCP), TraefikService, TLSOption, and ServersTransport (+TCP) — previously these fell through to the generic renderer. Middleware renders type-specific config (chain/auth/forwardAuth/ errors + generic fallback) showing secret references only, never values; TraefikService shows weighted/mirroring backends with weight bars. 4. Two reference-integrity audit checks: a Traefik router referencing a non-existent Service/TraefikService or Middleware. Traefik ships no admission webhook, so these dangle silently. Matching is conservative (only genuinely- absent refs, group-aware, synced informers only) to avoid false positives.
Avoids a partial-sync window where one target kind (e.g. middlewaretcps) is ready but another (middlewares) isn't, which could fabricate a transient 'missing reference' finding. Skip the round entirely until every watched Traefik GVR has synced; the next audit runs once they catch up.
…n link kind - redactConfig walks the generic middleware config at every depth, so a secret buried under e.g. plugin.config.clientSecret can't survive JSON.stringify (shallow redaction missed depth >= 2). - MiddlewareTCP chain member links now resolve to middlewaretcps, not middlewares.
getMiddlewareType returning 'unknown' left the Configuration section empty
because config was hardcoded to {}. Fall back to the spec's sole top-level key
so the raw config the banner promises actually renders (deep-redacted).
…action set - The Traefik audit sync-gate required EVERY watched Traefik GVR synced; an unsynced TLSOption/ServersTransport informer (irrelevant to the checks) would drop the whole scan. Gate only on the kinds the checks actually read. - The renderer's generic-config redaction set was narrower than the backend's (missed apiKey/privateKey/passphrase/...). Align it with the backend value-key set so plugin/unknown middleware configs can't leak those inline.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4b62077. Configure here.
Close the whole 'nested/array inline credential' class structurally: the generic (unknown/plugin) config view now renders only top-level scalars with credential keys redacted, and summarizes nested objects/arrays without their values. The frontend has no value-pattern redaction to safely classify an arbitrary nested string, and the full structure remains available in the YAML tab. Flat configs (rateLimit, redirectScheme) still render in full.
…erer config Reworks the Traefik dangling-ref audit around inventory authority, and fixes two redaction issues, per a deep review pass: - Drop Group from Traefik findings so the audit's builtin backfill leaves it "" — which is what the per-resource audit drill-down looks up. Findings were invisible on a route's own detail before (only the cluster-wide list showed them). - Resolve route refs against CLUSTER-WIDE target inventory (scope only the route subjects), so a legitimate cross-namespace Middleware/Service reference resolves instead of being fabricated as "missing" in a scoped audit. - Assert absence only for target kinds backed by a SYNCED, CLUSTER-WIDE informer (new DynamicResourceCache.IsClusterWideSynced). This single per-GVR gate fixes three issues together: partial-coverage false positives, Middleware-vs- MiddlewareTCP granularity, and one-stuck-informer suppressing the whole scan — each GVR is now independent. Under namespace-scoped caching the check skips (no finding) rather than risking a false positive. - Reword findings to "not found in the cluster" — Radar can't observe Traefik's allowCrossNamespace / provider namespace filters, so it only asserts inventory existence, not Traefik resolvability. - Redaction: add `users` to the backend sensitive-key set (aligns with the frontend mirror; covers htpasswd basicAuth entries). - Renderer: restore deep recursive credential-key redaction for generic/plugin middleware config (show non-secret nested values, hide credential keys at every depth) instead of collapsing all nested values — the drawer is not a secrecy boundary (the YAML tab shows the full spec).
… coverage Completes the coverage-gating: the missing-Service check now only asserts absence when the typed Services informer is cluster-wide (new ResourceCache.IsKindClusterWide), matching the gate already applied to the dynamic Middleware/TraefikService kinds. Under a namespace-scoped Services fallback the check skips rather than risk a false 'missing Service' — so all four Traefik ref-target kinds are now uniformly sound, with no residual gap.
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
A deep-dive into Traefik support surfaced four real gaps behind the (already broad) integration. This closes them: legacy-API-group support, a CRD-spec secret-redaction hole in the AI/MCP context, missing resource-detail renderers, and the absence of any Traefik best-practice checks. Each workstream is independent; they're bundled here as one PR.
What changed
1. Legacy
traefik.containo.usgroup (internal/k8s/dynamic_cache.go)Warm-list the 10 legacy-group CRDs next to the
traefik.ioblock. Discovery already resolved single-group clusters either way; this restores pre-warm parity so pre-v2.11 clusters don't pay first-list latency. True dual-served (traefik.io+containo.ussimultaneously) topology is rare/transient and tracked separately — not solved here.2. Key-aware secret redaction for CRD context (
pkg/ai/context/)RedactSecretspreviously ran only over log lines and env values; an inline credential in a CRD spec reached the LLM/get_resourceverbatim. NewRedactInlineSecretswalksspec/statusand redacts a string value when either its key is a value-bearing credential name (exact match:password,clientSecret,token, …) or the value matches a high-confidence pattern (prefixed tokens, AWS keys, bearer, htpasswd/crypt hashes).secretName,secretRef,rootCAsSecrets,basicAuth.secrethold the name of a Secret, which an operator needs to diagnose a bad reference.basicAuth.users, so the concrete inline-credential case is mostly v2/plugin/annotation territory; the value-pattern still catches hashes wherever they appear.)3. Traefik detail renderers (
packages/k8s-ui/.../renderers/)Middleware (+MiddlewareTCP), TraefikService, TLSOption, and ServersTransport (+TCP) previously fell through to the generic renderer. New renderers, registered in the dispatch (every added
KNOWN_KINDSplural has a matching render line — adding one without the other blanks the drawer):insecureSkipVerifywarning banner, CA/cert secret refs, timeouts.4. Reference-integrity audit checks (
pkg/audit/,internal/audit/runner.go)Two new Reliability checks — a router referencing a non-existent Service/TraefikService (
traefikRouteMissingService) or Middleware (traefikRouteMissingMiddleware). Traefik ships no admission webhook or linter, so these dangle silently until someone reads controller logs (Kubevious built a dedicated validator for exactly this). Mirrors the existingingressNoMatchingServicepattern.Sound under RBAC, by design. The central guarantee is inventory authority: the check asserts a "missing X" finding only when that target kind is served by a synced cluster-wide informer (
IsClusterWideSyncedfor the dynamic Middleware/TraefikService kinds;IsKindClusterWide("services")for core Services). When the cache only covers a namespace subset (RBAC-scoped fallback), it skips rather than fabricate a false "missing". Because cluster-wide coverage is authoritative for every namespace, that same gate lets it correctly resolve cross-namespace references too. Matching is group-aware (atraefik.iorouter isn't satisfied by atraefik.containo.ustarget) and per-kind independent (IngressRouteTCP→MiddlewareTCP resolves separately from Middleware, so a stuck/unwatched kind neither suppresses the others nor fabricates findings). Findings say "not found in the cluster" — Radar can't observe Traefik'sallowCrossNamespace/ provider namespace filters, so it asserts inventory existence, not Traefik resolvability. Scope is deliberately partial (route → Service/Middleware); nested TraefikService services, chain members,errors.service, and TLS-secret refs are not yet covered.Review
Heavily cross-reviewed. A
/plan-looppass with Codex surfaced the load-bearing constraint — under RBAC-scoped / namespace-fallback caching the audit cannot distinguish "object absent" from "not cached" — which reshaped the design around the cluster-wide inventory-authority gate above (rather than a naive "resolve against the cache" that would false-positive). Implementation diff + Bugbot passes then drove the redaction precision (secret references preserved;users/htpasswd entries redacted; nested credential keys hidden at every depth) and the renderer fixes (TCP-aware chain links, surgical deep-redact over blanket collapse). All confirmed findings fixed; the audit's four ref-target kinds are now uniformly coverage-gated.Testing
Unit:
make test(full Go suite) ✓ — incl.pkg/audit/traefik_test.go(cross-namespace ref resolves; non-authoritative kind skips; per-kind independence; group-aware matching; findings carry emptyGroupfor drill-down) andredact_test.go(key-aware redaction, secret-reference preservation, plaintext-usersredaction, high-confidence value catch).internal/k8sgreen, so the warm-list addition didn't break the RBAC-coverage / capability-alignment guards.make tsc✓.Live (kind cluster, Traefik v3 CRDs + fixtures):
get_resource: inline pluginapiKey/token→[REDACTED], aBearerheader value →Bearer [REDACTED], whilebasicAuth.secret(a reference name) and a benignendpointare preserved.Out of scope (considered, rejected)
Status badges (Traefik doesn't populate CRD
.status), standard-Ingress-via-Traefik association, entrypoint nodes, true dual-group topology.Note
Medium Risk
Touches audit false-positive logic and LLM-facing CRD redaction; changes are conservative (authority gates, reference preservation) but affect reliability findings and AI context for arbitrary CRDs.
Overview
This PR extends Traefik support across cache warmup, AI/MCP context safety, the resource drawer, and reliability audits.
Legacy API group — The dynamic cache warm-list now includes
traefik.containo.usalongsidetraefik.ioso older clusters avoid first-list latency on the same CRD set.CRD secret redaction —
RedactInlineSecretswalks unstructuredspec/statusbefore compact/detail minification, redacting credential keys and high-confidence patterns while keeping secret reference names. The Middleware drawer mirrors the same key set with nested(hidden)redaction.UI renderers — Middleware/MiddlewareTCP, TraefikService, TLSOption, and ServersTransport (+TCP) get dedicated drawers (chains, auth refs only, weighted/mirror backends, TLS settings, insecure-skip-verify warning) and are wired through
KNOWN_KINDSand dispatch.Audit — The runner loads namespace-scoped routes and cluster-wide middleware/TraefikService targets (both groups), gated by
IsClusterWideSynced/IsKindClusterWideso partial cache coverage never asserts “missing.” New checkstraefikRouteMissingServiceandtraefikRouteMissingMiddlewareflag broken refs within the same API group; nested TraefikService/chain refs are out of scope.Reviewed by Cursor Bugbot for commit 2354b4b. Bugbot is set up for automated code reviews on this repo. Configure here.