fix(users): align daniel uid/gid with kanidm (uid=1000, gid=1000) #496

Closed
lytedev wants to merge 4 commits from align-daniel-uid into main
Owner

Summary

Collapses the two-identity collision found in #495's wake (local daniel at uid 1000 gid 997, kanidm daniel at uid 2001 gid 2001) by aligning both on uid 1000 / gid 1000.

  • lib/modules/nixos/default-module.nix: pin users.users.daniel.uid = 1000 and users.groups.daniel.gid = 1000 (previously auto-allocated to 1000 and 997 respectively).
  • secrets/beefcake/kanidm-migrations.yml: add posixaccount class + gidnumber: 1000 to daniel's person entry so the posix attributes are reproducible from git instead of living only in kanidm's DB.
  • New systemd oneshot align-daniel-gid: on first boot post-deploy, chgrp any files under /home/daniel still at the old gid over to 1000. Idempotent via /var/lib/lyte/align-daniel-gid.done. Ordered before systemd-user-sessions.service. Safe to leave in tree; can be removed once every host has migrated.

Why this (rather than the fuller migrate-to-kanidm-only approach)

Having kanidm and nix agree on the numeric identity eliminates the collision symptoms (shadowed users, split group memberships, unreachable home dirs) with dramatically less churn than ripping out users.users.daniel. The break-glass properties of the local user are preserved. See issues/open/migrate-daniel-to-kanidm-only.md for the long-term plan if/when fuller separation becomes useful.

Caveats

  • The posixaccount class + gidnumber syntax in the migration HJSON format isn't explicitly documented in kanidm's example files — it's inferred from the attribute schema. First deploy to beefcake will confirm the migration applies cleanly. Revert is trivial if it rejects.
  • Daniel's gidnumber was previously set imperatively via kanidm person posix set-gidnumber (the value 2001 lived only in the SQLite DB). This PR is the first time the value is tracked in git.

Test plan

  • Deploy to a non-beefcake host (e.g. thinker). Verify id daniel returns uid=1000 gid=1000, files in /home/daniel chgrp'd successfully, marker file present.
  • Deploy to beefcake. Verify migration processes the updated daniel entry without error; kanidm reports daniel's gidnumber as 1000.
  • getent passwd daniel / getent passwd daniel@idm.h.lyte.dev both resolve to uid=1000.
  • getent group daniel returns a single unambiguous gid=1000 entry (duplicates from the pre-migration two-gid state go away).
  • SSH login as daniel still works on both cached and fresh (kanidm-only) authentication paths.
## Summary Collapses the two-identity collision found in #495's wake (local daniel at uid 1000 gid 997, kanidm daniel at uid 2001 gid 2001) by aligning both on uid 1000 / gid 1000. - `lib/modules/nixos/default-module.nix`: pin `users.users.daniel.uid = 1000` and `users.groups.daniel.gid = 1000` (previously auto-allocated to 1000 and 997 respectively). - `secrets/beefcake/kanidm-migrations.yml`: add `posixaccount` class + `gidnumber: 1000` to daniel's person entry so the posix attributes are reproducible from git instead of living only in kanidm's DB. - New systemd oneshot `align-daniel-gid`: on first boot post-deploy, chgrp any files under `/home/daniel` still at the old gid over to 1000. Idempotent via `/var/lib/lyte/align-daniel-gid.done`. Ordered before `systemd-user-sessions.service`. Safe to leave in tree; can be removed once every host has migrated. ## Why this (rather than the fuller migrate-to-kanidm-only approach) Having kanidm and nix agree on the numeric identity eliminates the collision symptoms (shadowed users, split group memberships, unreachable home dirs) with dramatically less churn than ripping out `users.users.daniel`. The break-glass properties of the local user are preserved. See `issues/open/migrate-daniel-to-kanidm-only.md` for the long-term plan if/when fuller separation becomes useful. ## Caveats - The `posixaccount` class + `gidnumber` syntax in the migration HJSON format isn't explicitly documented in kanidm's example files — it's inferred from the attribute schema. First deploy to beefcake will confirm the migration applies cleanly. Revert is trivial if it rejects. - Daniel's gidnumber was previously set imperatively via `kanidm person posix set-gidnumber` (the value 2001 lived only in the SQLite DB). This PR is the first time the value is tracked in git. ## Test plan - [ ] Deploy to a non-beefcake host (e.g. thinker). Verify `id daniel` returns uid=1000 gid=1000, files in `/home/daniel` chgrp'd successfully, marker file present. - [ ] Deploy to beefcake. Verify migration processes the updated daniel entry without error; kanidm reports daniel's gidnumber as 1000. - [ ] `getent passwd daniel` / `getent passwd daniel@idm.h.lyte.dev` both resolve to uid=1000. - [ ] `getent group daniel` returns a single unambiguous gid=1000 entry (duplicates from the pre-migration two-gid state go away). - [ ] SSH login as daniel still works on both cached and fresh (kanidm-only) authentication paths.
fix(users): align daniel uid/gid with kanidm posix attrs
All checks were successful
/ check-format (push) Successful in 8s
/ build (push) Successful in 5m57s
6e63b72f37
Pin local `users.users.daniel.uid = 1000` and `users.groups.daniel.gid = 1000`
to match kanidm's posix attributes. Previously nix auto-allocated uid=1000
gid=997 while kanidm had daniel at uid=2001 gid=2001, creating two distinct
identities for the same name. After also setting kanidm's gidnumber to 1000
(enshrined in the SOPS-encrypted persons migration), NSS entries from both
sources describe the same numeric identity and the shortname/SPN collision
that started this thread resolves.

Includes a one-shot systemd unit (`align-daniel-gid`) that chgrps any
surviving files owned by the old gid 997 over to 1000 on first boot after
deploy. Idempotent via a marker at /var/lib/lyte/align-daniel-gid.done.
Ordered before `systemd-user-sessions.service` so migration completes
before login. Safe to leave in tree; can be removed once every host has
run it.

Related: issues/open/migrate-daniel-to-kanidm-only.md
lytedev force-pushed align-daniel-uid from 6e63b72f37
All checks were successful
/ check-format (push) Successful in 8s
/ build (push) Successful in 5m57s
to 6bc26dd084
Some checks failed
/ build (push) Waiting to run
/ check-format (push) Has been cancelled
2026-04-18 10:00:20 -05:00
Compare
fix(users): align daniel uid/gid with kanidm posix attrs
Some checks failed
/ check-format (push) Successful in 7s
/ build (push) Has been cancelled
8fe03fec40
Pin local `users.users.daniel.uid = 1000` and `users.groups.daniel.gid = 1000`
to match kanidm's posix attributes. Previously nix auto-allocated uid=1000
gid=997 while kanidm had daniel at uid=2001 gid=2001, creating two distinct
identities for the same name. After also setting kanidm's gidnumber to 1000
(enshrined in the SOPS-encrypted persons migration), NSS entries from both
sources describe the same numeric identity and the shortname/SPN collision
that started this thread resolves.

Includes a one-shot systemd unit (`align-daniel-gid`) that chgrps any
surviving files owned by the old gid 997 over to 1000 on first boot after
deploy. Idempotent via a marker at /var/lib/lyte/align-daniel-gid.done.
Ordered before `systemd-user-sessions.service` so migration completes
before login. Safe to leave in tree; can be removed once every host has
run it.

Related: issues/open/migrate-daniel-to-kanidm-only.md
fix(users): use direct binary paths + awk for align-daniel-gid
All checks were successful
/ check-format (push) Successful in 7s
/ build (push) Successful in 5m21s
ddbb9674aa
Previous version put glibc in PATH but getent lives in a split 'getent'
output that nixpkgs doesn't expose via the main package, so the unit
failed with 'getent: command not found'. Switch to awk against
/etc/group for the lookups — no NSS dependency, no PATH surprises,
works during early boot.
fix(users): tolerate chgrp failures on read-only nix-store paths
All checks were successful
/ check-format (push) Successful in 7s
/ build (push) Successful in 5m13s
011243c51b
.direnv/flake-inputs/* are bind-mounted from the nix store (read-only)
and lyte.userSymlinks creates symlinks pointing into the store. chgrp
fails on both — expected, not an error. Use -h (modify symlink itself,
don't follow) and ignore the overall exit code so one-shot completes.
Author
Owner

Superseded — approach shifted to letting kanidm fully own uid/gid (UUID-derived) rather than pinning both sides to 1000. Replacement PR coming with the kanidm-takeover migration.

Superseded — approach shifted to letting kanidm fully own uid/gid (UUID-derived) rather than pinning both sides to 1000. Replacement PR coming with the kanidm-takeover migration.
lytedev closed this pull request 2026-04-18 11:54:57 -05:00
All checks were successful
/ check-format (push) Successful in 7s
Required
Details
/ build (push) Successful in 5m13s
Required
Details

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lytedev/nix!496
No description provided.