Repository navigation
kubeflow: make auth.oidc.* reach Dex and oauth2-proxy when set with -f/--set - #40
Conversation
|
@UniversalBasicInc Thanks for the PR! The changes look good. We can approve and merge it once the conflicts are resolved. |
87f4b74 to
288fd43
Compare
|
Thanks! Rebased onto current main and resolved the conflicts with #41 (kept both guards in validations.yaml and the new oauth2-proxy note in values.yaml). The render checks still pass, including with the new native ext_authz values. |
|
Findings from AI assisted code-review:
The PR newly introduces auth.oidc.clientId and documents it as authoritative ("OIDC client ID written to the shared Secret"). But the client id lives as a literal in three unconnected places, and only one is wired to the new knob: ┌──────────────────────────────────────────────────────────────┬───────────────────────────────┐ Dex consumes the shared secret only for the client-secret (secretEnv), never for the id. So overriding auth.oidc.clientId makes oauth2-proxy present the new id while Dex still only knows kubeflow-oidc-authservice → invalid_client → login fails. This is the same class of bug the PR sets out to eliminate, re-introduced for clientId, and unlike clientSecret/cookieSecret there is no validation guarding it. Confirmed by render: --set auth.oidc.clientId=my-custom-client yields secret/oauth2-proxy = my-custom-client, Dex still kubeflow-oidc-authservice. Defaults match, so out-of-the-box installs are fine — it only bites an operator who trusts the docs and overrides it. Three ways to fix (pick one):
dex.oidcClientId is now read by nothing (the dex-idp subchart doesn't consume it; it was already dead pre-PR). dex.oidcClientSecret survives only so the new validation can detect misuse — that's fine — but consider removing dex.oidcClientId or commenting it as unused.
auth.oidc.* (including the new clientId/existingSecret) isn't in the schema — pre-existing gap, and auth has no additionalProperties: false, so nothing fails. Adding existingSecret as type: boolean would catch the classic existingSecret: "false" string footgun (string → truthy → secret silently skipped → pods reference a missing secret). Optional.
OIDC gets a real fix (shared secret); SeaweedFS only gets a fail-fast guard. This changes behavior: --set pipelines.seaweedfs.accessKey=x alone now hard-fails the render where it previously rendered (silently broken). Fail-fast is the better behavior, but it's a visible change worth a release note. Scoping it this way is defensible (OIDC was the filed bug).
The new secrets/oidc-client-Secret.yaml uses namespace: {{ .Release.Namespace }} + app.kubernetes.io/* labels, while its sibling cloudflare-api-token-Secret.yaml hardcodes namespace: kubeflow with no labels. The new template is actually the better pattern — just inconsistent with its neighbor. Testing note Full-chart helm template fails in this workspace on a pre-existing migration guard (validations.yaml:126, removed ingress-gateway keys) that trips on the locally-vendored subchart defaults — unrelated to this PR (the keys are untouched, and it fails identically on main). I validated the OIDC wiring on an isolated copy with only that guard neutralized. The PR's own new CI render step looks correct and genuinely exercises the fix. Verdict Solid, well-tested fix for #28 with good fail-fast guards and a real security tidy-up. Finding #1 should block merge — auth.oidc.clientId reproduces the exact footgun the PR eliminates, with no guard, because Dex consumes the shared secret for the credential alone and not the id. Everything else is low-severity or optional. Recommend fix option B (or idEnv if clientId must stay configurable), then merge. |
…f/--set values.yaml copies auth.oidc.clientSecret/cookieSecret into the Dex and oauth2-proxy values (and pipelines.seaweedfs.* into user-namespace) with YAML anchors. Anchors are resolved when values.yaml itself is parsed, so values supplied with -f or --set update only the source keys, not the copies. When Dex's static client secret is set explicitly but oauth2-proxy's copy is not updated, the two no longer match and login fails after Dex with HTTP 500 "invalid_client" (SUSE#28). - Create one Secret, kubeflow-oidc-client, from auth.oidc.*. oauth2-proxy reads it via config.existingSecret and Dex via envVars + staticClients[].secretEnv, so values set either way reach both. auth.oidc.existingSecret=true lets operators supply the Secret themselves. - validations.yaml: fail at render time if a remaining copy (Dex, oauth2-proxy, user-namespace SeaweedFS keys) differs from its source, and if auth.oidc.cookieSecret is a length oauth2-proxy would reject (16/24/32 bytes raw, or URL-safe base64 decoding to that), now that the value reaches it. - CI: render with auth.oidc.* overrides and assert they reach Dex and oauth2-proxy, and that mismatched SeaweedFS copies fail the render. - Docs: production and access guides use secretEnv and generate the cookie secret as URL-safe base64; document rotating the OIDC secrets (restart Dex and oauth2-proxy); the values reference documents auth.oidc.clientId and auth.oidc.existingSecret, and notes that dex.existingOidcClientSecret is not read by this chart. Fixes SUSE#28 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
288fd43 to
461cf2e
Compare
|
Thanks for the thorough review! Pushed an update:
The repro checks still pass on the updated branch, including the CI render step. |
Fixes #28.
Problem
values.yamlcopiesauth.oidc.clientSecret/cookieSecretinto the Dex and oauth2-proxy values (andpipelines.seaweedfs.*intouser-namespace) using YAML anchors. Anchors are resolved whenvalues.yamlitself is parsed, so values supplied with-for--setupdate only the source keys, not the copies. When Dex's static client secret is set explicitly but oauth2-proxy's copy isn't updated, the two no longer match and login fails after Dex with HTTP 500invalid_client. Editingvalues.yamldirectly is not affected.Change
kubeflow-oidc-client, built fromauth.oidc.*. oauth2-proxy reads it viaconfig.existingSecret, Dex viaenvVars+staticClients[].secretEnv, so values set either way reach both.auth.oidc.existingSecret: truelets operators provide the Secret themselves.validations.yaml: the render fails if a remaining copy (Dex, oauth2-proxy, user-namespace SeaweedFS keys) differs from its source, or ifauth.oidc.cookieSecretis a length oauth2-proxy would reject.auth.oidc.*overrides reach Dex and oauth2-proxy, and that mismatched SeaweedFS copies fail the render.secretEnvand URL-safe base64 cookie secrets; a note on rotating the OIDC secrets; the values reference coversauth.oidc.existingSecret(the client id is fixed tokubeflow-oidc-authservice, the id Dex registers) and notes thatdex.oidcClientIdanddex.existingOidcClientSecretare not read by this chart; an upgrade note indocs/upgrade-notes.md.Compatibility
Existing values files keep working, including ones that set Dex's
staticClients[].secretexplicitly.Testing
helm lintpasses; the new CI step passes on this branch and fails onmain.main, a values file that sets the client secret reproduces the HTTP 500; on this branch, login succeeds.APPCO_TOKEN, like the existing render steps.This change was developed with assistance from Claude (Anthropic); I reviewed and tested every part of it.
🤖 Generated with Claude Code