Keycloak realm: converge with keycloak-config-cli, drop realmFiles, add the LDAP group mapper #277
Labels
No labels
bug
enhancement
in-progress
needs-info
needs-triage
p0
ready-for-agent
ready-for-human
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/nixos#277
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of #266. Follows #271, which passed the M3 gate: Keycloak serves
sso.cloonar.com, SPNEGO works from anbdesktop session, and LDAP password login works as the fallback.Replace
services.keycloak.realmFileswith a converging import viakeycloak-config-cli, and prove it by landing the LDAP group mapper — the first realm change thatrealmFilesstructurally cannot apply.Why
realmFilesis create-if-absent: Keycloak skips the import entirely once the realm exists. Thecloonarrealm exists, so every further edit tocloonar-realm.jsonis a silent no-op. Nothing else in M4–M6 can ship until this changes.pkgs.keycloak-config-cli(6.5.1, Maven build) talks to Keycloak's Admin REST API, computes the delta between the files and the live realm, applies only what differs, and needs no restart. ADR-0022 deferred this decision to M4; it is now due.The hazard — read before writing any code
import.managed.*defaults tofull, meaning the first run deletes anything present in the realm but absent from the YAML. The realm currently holds the LDAP provider, sixuser-attribute-ldap-mappers, and the custombrowser-spnegoflow that the M3 gate depends on. An incomplete port silently strips SPNEGO, and the symptom looks like a Keycloak bug rather than a missing stanza.Therefore land this as two commits:
cloonar-realm.jsoninto config-cli's format with no intended changes, switch the mechanism over, and confirm the converge run is a no-op — realm unchanged, SPNEGO still working.Do not loosen
import.managed.*tono-deleteto dodge this. Half-managed config is worse than either extreme, and full management is the point.Scope
1. Converging import
pkgs.keycloak-config-clias aType = "oneshot"unit,after/requireskeycloak.service,wantedBy = multi-user.target.--keycloak.availability-check.enabled).keycloak.servicereachingactivedoes not mean the Admin API accepts requests; without this the unit races Keycloak's startup and fails intermittently.--import.files.locationsat a store path holding the realm files. Because the store path changes when the files change,switch-to-configurationrestarts the unit exactly when the config changes and stays quiet otherwise — no timer, no polling, and it composes correctly with bento's five-minute loop.masterrealm; the realm being managed iscloonar.2. Secrets — none to add
keycloak-bootstrap-admin, but underKC_BOOTSTRAP_ADMIN_USERNAME/KC_BOOTSTRAP_ADMIN_PASSWORD, while config-cli wantsKEYCLOAK_USER/KEYCLOAK_PASSWORD. Translate in-module — render an env file in anExecStartPre, the waymaterialiseSecretsinhosts/web-arm/modules/keycloak/default.nixalready does. Do not add a second sops key holding a duplicate password.${vault.ldapbind}, Keycloak resolves it at runtime, and the credential never enters config-cli's environment or Keycloak's database.import.var-substitutiondisabled. With substitution on,${vault.ldapbind}risks being interpreted as a substitution token and mangled — which would break the LDAP bind in a way that looks like a wrong password.linuxbind-password. It already backs SSSD onnbandweb-armplus the SSHAuthorizedKeysCommand; a copy that drifts on rotation would take SSH access with it.A dedicated Keycloak service account with only
realm-managementroles is the better end state than the master admin, but it is a chicken-and-egg to bootstrap. Note it as future hardening; use the admin user now.3. Drop
realmFilesRemove
services.keycloak.realmFilesand let config-cli own the realm end to end, including creating it if absent. Two mechanisms writing the same realm — one create-only at startup, one converging over the API — is a confusing split with no upside.4. The group mapper (second commit)
A
group-ldap-mapperon thecloonar-ldapprovider:groups.dn = ou=groups,dc=cloonar,dc=comgroup.object.classes = groupOfNames,group.name.ldap.attribute = cnmembership.ldap.attribute = member,membership.attribute.type = DNThis is the web-services group tree, and it is deliberately not the one SSSD uses. The directory carries two group schemas on purpose:
cn=linux,ou=groupsholds POSIX groups withmemberUid(rfc2307) for Unix logins, whileou=groupsholdsgroupOfNameswithmemberfor web authorization.hosts/web-arm/modules/authelia.nix:77is the working precedent for the latter. TheobjectClassfilter keeps the POSIXcn=linuxgroup out of Keycloak's view.Set
preserve.group.inheritance = falseunless the group tree is genuinely hierarchical — with flat groups underou=groups, leaving it true makes the sync fail.Expected to appear:
Administrators,Mitarbeiter,macher.solutions,immich(the groupsauthelia.nixpolicies reference). Choosemode(LDAP_ONLYvsREAD_ONLY) deliberately and say why in a comment — the federation is READ_ONLY.5. Correct a stale comment
hosts/nb/modules/ldap-login.nix:42-46describes the two group schemas as an unresolved contradiction withauthelia.nix:77. They are deliberately different bases for different consumers, as above. Fix the comment; the SSSD config itself is correct and must not change.6. ADR
Amend
docs/adr/0022-keycloak-and-scoped-kerberos.md: the declarative-configuration question is now answered. Recordkeycloak-config-cli, thatrealmFileswas create-only and why that made it insufficient, themanaged = fullconsequence (the admin console becomes effectively read-only — UI changes get reverted on the next converge), and that the Maven build is a cost accepted on a substituter-less arm64 host.Out of scope
admin-only/internal/immichpolicies have no direct Keycloak equivalent and need a per-client authentication-flow design. Separate issue.hosts/mail/*; anything onnbbeyond the comment fix.Verification
scripts/pre-commitdry-buildsweb-arm. Do not runscripts/test-configurationmanually.Human, after deploy:
systemctl status keycloak-config— succeeded, and the journal shows the first (verbatim) run applying no changes.dominik.polakovicssession onnbwith a TGT,https://sso.cloonar.com/realms/cloonar/accountloads with no prompt. This is the regression that matters.Administrators,Mitarbeiter,macher.solutions,immichpresent, with the expected members.cn=linuxabsent.Also worth doing while in the console, though not part of this issue: check the user list for
linuxbind,vmail,authelia,owncloud,netdata.searchScope = 2withusersDn = ou=usersenclosesou=system,ou=users, so service accounts may be exposed as login-able users. That must be resolved before clients are wired up.Definition of done
realmFilesgone; realm managed bykeycloak-config-cli.authelia.nixor any existing vhost.ldap-login.nixcomment corrected.Closes #<this issue>.