dex: configure connectors through values - #3568
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Pull request overview
Adds configurable Dex identity-provider connectors, external credential Secrets, and private certificate authority support.
Changes:
- Adds connector configuration and validation safeguards.
- Mounts credential and certificate authority Secrets.
- Adds documentation and automated Helm tests.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_dex_helm_connectors.py |
Tests connector rendering and validation. |
common/dex/helm/values.yaml |
Defines new connector and Secret values. |
common/dex/helm/templates/validate-config.yaml |
Validates connector configuration. |
common/dex/helm/templates/dex.yaml |
Mounts and exposes external Secrets. |
common/dex/helm/templates/config-map.yaml |
Renders connectors conditionally. |
common/dex/helm/templates/_helpers.tpl |
Defines the certificate authority mount path. |
common/dex/helm/README.md |
Documents connector configuration and credentials. |
.github/workflows/helm-kustomize-comparison.yml |
Executes the new tests. |
Suppressed comments (2)
tests/test_dex_helm_connectors.py:224
- The single-letter
vhides that the comprehension iterates over volumes and violates the expressive-naming requirement inAGENTS.md:7. Usevolumehere.
volumes = [v["name"] for v in deployment["spec"]["template"]["spec"]["volumes"]]
tests/test_dex_helm_connectors.py:329
caabbreviates certificate authority even thoughAGENTS.md:7requires explicitly long, expressive names. Spell outcertificate_authorityin this test name.
def test_a_non_normalized_root_ca_path_is_rejected(self):
| {{- if and (not .Values.config.enablePasswordDB) (not .Values.config.connectors) }} | ||
| {{- fail "config.enablePasswordDB is false and config.connectors is empty, so Dex would have no way to authenticate anyone; configure a connector or keep the password database enabled" }} | ||
| {{- end }} |
| kubectl create secret generic keycloak-oidc-credentials \ | ||
| --namespace auth \ | ||
| --from-literal=KEYCLOAK_CLIENT_ID=kubeflow \ | ||
| --from-literal=KEYCLOAK_CLIENT_SECRET=<client secret> |
| {{- if or (contains "/./" $certificate) (contains "/../" $certificate) }} | ||
| {{- fail (printf "config.connectors[%d] rootCAs entry %s is not a normalized path; write it without . or .. segments" $index $certificate) }} |
| The chart does not create these Secrets. They must exist before the release is | ||
| installed. |
| configuration = self.dex_configuration(result.stdout) | ||
| self.assertNotIn("staticPasswords", configuration) | ||
| self.assertFalse(configuration["enablePasswordDB"]) | ||
| self.assertEqual([c["id"] for c in configuration["connectors"]], ["keycloak"]) |
| mount = next( | ||
| m | ||
| for m in pod["containers"][0]["volumeMounts"] | ||
| if m["mountPath"] == "/etc/dex/certificate-authorities" | ||
| ) | ||
| self.assertTrue(mount["readOnly"]) |
| v | ||
| for v in pod["volumes"] | ||
| if v["name"] == "connector-certificate-authorities" |
| volumes = [v["name"] for v in deployment["spec"]["template"]["spec"]["volumes"]] | ||
| self.assertEqual(volumes, ["config"]) | ||
|
|
||
| def test_root_ca_path_without_the_secret_fails(self): |
aeda73e to
caf552e
Compare
Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
caf552e to
d429ab2
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Boolean and path validation accept inputs that produce unusable Dex configurations, and the documented Secret command is invalid Bash syntax.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
tests/dex_helm_connectors_test.py:209
- The one-letter name
vhides that this expression selects a volume. Use the explicitvolumename required by the repository naming standard.
v
for v in pod["volumes"]
if v["name"] == "connector-certificate-authorities"
tests/dex_helm_connectors_test.py:224
- The one-letter name
vobscures that this comprehension iterates volumes. Use the explicitvolumename required by the repository naming standard.
volumes = [v["name"] for v in deployment["spec"]["template"]["spec"]["volumes"]]
- Files reviewed: 8/8 changed files
- Comments generated: 6
- Review effort level: Balanced
| {{- if and (not .Values.config.enablePasswordDB) (not .Values.config.connectors) }} | ||
| {{- fail "config.enablePasswordDB is false and config.connectors is empty, so Dex would have no way to authenticate anyone; configure a connector or keep the password database enabled" }} | ||
| {{- end }} |
| {{- if not (or (kindIs "slice" .Values.config.connectors) (kindIs "invalid" .Values.config.connectors)) }} | ||
| {{- fail (printf "config.connectors must be a list of Dex connectors; got %s" (kindOf .Values.config.connectors)) }} | ||
| {{- end }} |
| {{- if or (contains "/./" $certificate) (contains "/../" $certificate) }} | ||
| {{- fail (printf "config.connectors[%d] rootCAs entry %s is not a normalized path; write it without . or .. segments" $index $certificate) }} | ||
| {{- end }} |
| kubectl create secret generic keycloak-oidc-credentials \ | ||
| --namespace auth \ | ||
| --from-literal=KEYCLOAK_CLIENT_ID=kubeflow \ | ||
| --from-literal=KEYCLOAK_CLIENT_SECRET=<client secret> |
| configuration = self.dex_configuration(result.stdout) | ||
| self.assertNotIn("staticPasswords", configuration) | ||
| self.assertFalse(configuration["enablePasswordDB"]) | ||
| self.assertEqual([c["id"] for c in configuration["connectors"]], ["keycloak"]) |
| mount = next( | ||
| m | ||
| for m in pod["containers"][0]["volumeMounts"] | ||
| if m["mountPath"] == "/etc/dex/certificate-authorities" | ||
| ) |
Pull Request Template for Kubeflow Manifests
✏️ Summary of Changes
Makes replacing the Dex login flow a values change.
Out of the box Dex authenticates against a static password database holding a
single demonstration account. Every real installation has to replace that with a
company identity provider. Until now the chart hardcoded the shape of
config.yamland exposed no way to add a connector, so the only route wasrewriting the ConfigMap by hand, as
common/dex/README.mddescribes.Connectors
Each entry is passed to Dex exactly as written, so any connector the
Dex documentation describes works — OIDC,
LDAP, GitHub, Microsoft, SAML — without the chart needing to know about it. Only
type,idandnameare required by the chart; everything underconfigbelongs to Dex.
Credentials stay out of
values.yamlDex resolves
$VARIABLEreferences from its environment.extraEnvironmentSecretsnames existing Secrets in the
authnamespace, which the chart appends to thecontainer's
envFrom:The chart does not create those Secrets. They must exist before the release is
installed.
Providers behind a private certificate authority
Dex reads connector certificate authorities from files —
rootCAsis a listof paths, read with
os.ReadFile— so a Secret alone is not enough. The chartmounted only its own ConfigMap, which left an operator whose identity provider
uses a private authority with no option except
insecureSkipVerify: true,disabling certificate verification altogether.
The Secret is mounted read-only at
/etc/dex/certificate-authorities. The LDAPconnector takes the certificate inline through
rootCADataand is unaffected.Guards
config.enablePasswordDB: falsewith no connector is rejected. OtherwiseDex starts with no way to authenticate anyone, which locks every user out.
config.connectorsmust be a list, and each connector must declaretype,idandname. Both fail before anything renders.rootCAspath under/etc/dex/certificate-authoritieswith noconnectorCertificateAuthoritySecretis rejected, rather than starting Dexwith a certificate it cannot read.
Two related fixes
staticPasswordswas rendered unconditionally, so disabling the passworddatabase left a dangling entry. Dex ignored it, but it read as sloppy. It is now
rendered only when the password database is enabled.
Changing a connector changes the configuration checksum on the Deployment, so
helm upgraderestarts the pods and the new configuration takes effect. There isa test for this, because a configuration change that does not restart the
workload silently does nothing.
Parity is unaffected
config.connectorsdefaults to empty andextraEnvironmentSecretsto an emptylist, so the rendered output is unchanged and the Kustomize comparison still
passes for every component. Connector configurations have no Kustomize
counterpart to compare against, so they are covered by unit tests instead.
📦 Dependencies
None. Applies to the merged Dex chart and is independent of every open pull
request.
🐛 Related Issues
Raised during review of #3524: "How can i disable for example the default login
flow? what are the things i can easily configure?" The login flow belongs to
this chart rather than the Dashboard chart, and it was not configurable. Now it
is.
Validation
Verified locally against Helm 4.1.0 and Kustomize v5.8.1.
✅ Contributor Checklist