docs(operations): tenant Kubernetes cluster OIDC#591
Conversation
Operator-facing page covering per-tenant Keycloak realms and OIDC on tenant kube-apiservers — companion to the existing OIDC docs which cover the management cluster (`cozy` realm). Pairs with cozystack PR cozystack/cozystack#3044. Covers: - the auto-provisioning flow (apps/tenant lookup → realm + scope → _namespace.oidc-realm → apps/kubernetes per-cluster client / group / kube-apiserver flags → in-cluster ClusterRoleBinding via Job); - the enable-on-a-Kubernetes-CR workflow; - creating users and granting access in the tenant realm; - wiring kubectl with kubelogin; - the four known limitations (orphan realm because helm-controller does not re-render on Helm `lookup` result changes; no caBundle / self-signed Keycloak; hardcoded JWT username/groups claims; CRB orphan on runtime oidc.enabled=true→false toggle); - troubleshooting (401 with valid token, 403 for in-group user, stuck realm/scope after CR deletion). Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
✅ Deploy Preview for cozystack ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughAdds a new documentation page for tenant-cluster OIDC authentication, covering enablement, access setup, kubelogin configuration, limitations, and troubleshooting for Kamaji-backed tenant Kubernetes clusters. ChangesTenant OIDC documentation
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~3 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces documentation for configuring OIDC authentication on tenant Kubernetes clusters managed by Cozystack. The feedback suggests correcting a kubectl patch command to use the proper KeycloakClient field name (directAccessGrantsEnabled instead of directAccess) and improving a troubleshooting command by replacing a fragile jsonpath and tr pipeline with a robust go-template format.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| kubectl -n <tenant-namespace> patch keycloakclient kubernetes-<cluster> \ | ||
| --type=merge --patch '{"spec":{"directAccess":true}}' |
There was a problem hiding this comment.
There is a discrepancy between the text and the patch command. The text mentions directAccessGrantsEnabled, but the patch command uses directAccess. In standard Keycloak Operators, the field is typically spec.client.directAccessGrantsEnabled or spec.directAccessGrantsEnabled. Please update the patch command to use the correct field name to ensure it works as expected.
| kubectl -n <tenant-namespace> patch keycloakclient kubernetes-<cluster> \ | |
| --type=merge --patch '{"spec":{"directAccess":true}}' | |
| kubectl -n <tenant-namespace> patch keycloakclient kubernetes-<cluster> \ | |
| --type=merge --patch '{"spec":{"client":{"directAccessGrantsEnabled":true}}}' |
| kubectl --context=mgmt -n <tenant-ns> get pod \ | ||
| -l kamaji.clastix.io/name=<cluster> \ | ||
| -o jsonpath='{.items[0].spec.containers[?(@.name=="kube-apiserver")].args}' | \ | ||
| tr ',' '\n' | grep oidc |
There was a problem hiding this comment.
Using jsonpath with tr ',' '\n' to parse container arguments is fragile because modern versions of kubectl format array fields as space-separated strings rather than comma-separated JSON-like arrays, which would cause tr to have no effect. Using go-template is a much more robust and built-in way to print container arguments one per line across all kubectl versions.
| kubectl --context=mgmt -n <tenant-ns> get pod \ | |
| -l kamaji.clastix.io/name=<cluster> \ | |
| -o jsonpath='{.items[0].spec.containers[?(@.name=="kube-apiserver")].args}' | \ | |
| tr ',' '\n' | grep oidc | |
| kubectl --context=mgmt -n <tenant-ns> get pod \ | |
| -l kamaji.clastix.io/name=<cluster> \ | |
| -o go-template='{{range (index .items 0).spec.containers}}{{if eq .name "kube-apiserver"}}{{range .args}}{{.}}{{\"\n\"}}{{end}}{{end}}{{end}}' | grep oidc |
Adversarial pass on the page from the prior commit found ten issues that would either confuse the reader or break the doc on render. Fixes: * Drop the `helm get notes` recipe — Cozystack uses Flux helm-controller, not a local helm CLI, so the command would not work for most operators. Replace with an explicit `kubectl get secret … | base64 -d` recipe that extracts the admin kubeconfig and dumps the cluster CA. * Clarify the cross-link to `self-signed-certificates.md` — the management cluster workaround there does NOT apply to tenant apiservers (Kamaji owns their machine config, not the operator's Talos / talm flow). The prior phrasing implied a tenant workaround existed. * Replace the optimistic "Within ≤ 5 minutes" with "up to ~10 minutes worst case" — the cascade is two sequential reconcile loops, not one, so 5 minutes was misleading for cold-start installs. Also document the `<release>-awaiting-oidc-realm` ConfigMap beacon between the two reconciles. * Rename the "Runtime toggle of `oidc.enabled` from `true` to `false`" heading to "Runtime oidc.enabled toggle does not clean up bindings" — Hugo's TOC generator does not always cope with inline `code` in headings, and the new wording is more declarative anyway. * Spell out the admin-kubeconfig extraction in every troubleshooting and cleanup recipe instead of leaving an `<admin-kubeconfig>` placeholder. * Pin one set of placeholders for the whole page (tenant = `acme`, cluster = `prod-a`, root host = `acme.example.com`) and use them consistently in every example. The earlier draft mixed concrete and `<placeholder>` style across sections. * Spell out the Job name (`kubernetes-prod-a-oidc-rbac`) rather than leaving `<release-name>-oidc-rbac` to be derived by the reader. * Rewrite "no realm group matches against the now-disabled OIDC path" to the clearer "no realm group can match it once OIDC is off". * Add an upfront `Tenant.spec.oidc.enabled` clarification: the field stays at its default `false` during normal operation, and the only legitimate use is the realm-cleanup workaround in Limitations. The prior draft mentioned the flag in two contexts without flagging that one of them was a workaround only. * Add a top-of-page placeholder index so the reader can map the example names back to their own deployment. Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
be7368b to
febf81d
Compare
…dant flag, add tests, rewrite docs Self-review of the recent oidc refactor surfaced six issues. Pre-commit on the previous push also failed because two regenerated artifacts weren't refreshed locally before commit. All addressed in one batch. Pre-commit recovery: * packages/apps/tenant/README.md — refreshed by cozyvalues-gen to match the flattened `oidc: bool` value (was still rendering the old struct shape). * packages/system/tenant-rd/cozyrds/tenant.yaml — keysOrder regenerated by hack/update-crd.sh; lists `oidc` after `resourceQuotas` (matches the order in api/tenant/types.go after the flatten). Real bugs the new unittest caught: * packages/extra/oidc/templates/admin-user.yaml — `index .Values._cluster "root-host"` nil-panicked when `_cluster` was absent (helm template standalone, helm-unittest fixtures without `_cluster` set). In production `_cluster` is always populated by apps/tenant via cozystack-values; the panic only surfaces in test environments and blocked the new unittest. Guard with `.Values._cluster | default dict` before the index. Cosmetic: * Drop `keepResource: true` from KeycloakRealmUser — the CRD default is already `true`, the explicit field was verbose dead text. New helm-unittest coverage for packages/extra/oidc/: * tests/admin_secret_test.yaml — asserts the keycloak-admin Secret carries the expected fields, the realm-admin user CR points at the right realm + the right passwordSecret + the right realm-management client role mapping, and the chart survives missing `_cluster` (the regression test that caught the panic above). * tests/realm_test.yaml — asserts ClusterKeycloakRealm + KeycloakClientScope groups render with the right shape, the v1.edp.epam.com capability guard suppresses them in bootstrap, session-lifetime overrides propagate. * `make test` was already there; it just had nothing to run. Documentation rewrite — the previous docs described the old inline auto-provision architecture and referenced names (`kubernetes-<cluster>`, `Tenant.spec.oidc.enabled` struct, lookup-based child detection) that no longer exist: * docs/oidc-tenant.md — rewritten end-to-end. Explains the tenant-module pattern + the realm inheritance behaviour + the realm-admin Secret + the new namespace-prefixed Keycloak identifiers. Adds a new Limitation section covering "disabling parent OIDC while descendant clusters use the inherited realm" (eventually consistent, bounded by helm-controller reconcile interval). * /tmp/website/content/en/docs/next/operations/oidc/tenant_clusters.md — same rewrite for the user-facing operator docs on the website side (commit lives in cozystack/website#591). E2E coverage gap intentionally not addressed in this commit — adding a multi-tenant inheritance test (parent owns realm, child Kubernetes CR wires against it) would extend the e2e sandbox runtime by ~5-10 min and is better tracked as a follow-up. Validated: * apps/tenant helm-unittest: 16/16 PASS * apps/kubernetes helm-unittest: 140/140 PASS * extra/oidc helm-unittest: 8/8 PASS (NEW) * bats parses (12 tests) Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
The previous version of this page described the inline-auto-provision architecture where apps/tenant rendered the realm directly and used Helm lookup to detect child Kubernetes CRs. That design is gone — realm provisioning now lives in extra/oidc, gated by a plain Tenant.spec.oidc bool (same shape as etcd / monitoring / ingress). Rewrite covers: * The tenant-module pattern (Tenant.spec.oidc=true → apps/tenant renders an `oidc` HR → extra/oidc provisions realm + admin user + keycloak-admin Secret). * The keycloak-admin Secret in the tenant namespace (url + username + password + realm), surfaced through the dashboard via spec.secrets.include. * Realm inheritance — descendant tenants inherit the parent's realm through _namespace.oidc-realm; realm-wide unique Keycloak identifiers (<tenant-namespace>-kubernetes-<cluster>) prevent sibling collisions. * Identity-admin delegation living with the realm-owning tenant only. * Limitation: disabling parent OIDC while descendant clusters use the inherited realm — eventually consistent within one helm-controller reconcile interval. Pairs with cozystack#3044 commit 2e52384c1. Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
What this PR does
Adds an operator-facing docs page for the new per-tenant Keycloak realm + OIDC-on-tenant-kube-apiserver feature. Companion to cozystack/cozystack#3044 which lands the chart implementation.
Lives in
next/operations/oidc/tenant_clusters.md(under the existing OIDC operations section that already covers the management cluster). Cross-links to the existingenable_oidc.mdpage so readers can tell the two flows apart.Sections
apps/tenantlookup→ realm + scope →_namespace.oidc-realm→apps/kubernetesper-cluster client / group / kube-apiserver flags → in-clusterClusterRoleBindingvia post-install Job.kubectlwith kubelogin.lookupresult changes, nocaBundle/ self-signed Keycloak support, hardcoded JWTpreferred_username/groupsclaims, CRB orphan on runtimeoidc.enabledtoggle.Release note
```release-note
docs(operations): document per-tenant Keycloak realm and OIDC on tenant Kubernetes clusters. Covers the auto-provisioning flow (apps/tenant lookup → realm → apps/kubernetes per-cluster client / group / kube-apiserver flags → in-cluster ClusterRoleBinding), kubelogin setup, the four known limitations (Helm lookup non-reactivity, no self-signed Keycloak, hardcoded claims, runtime toggle), and troubleshooting.
```
Summary by CodeRabbit