From b845a8bb8b9cbad365fc4a491d67166eb7694e51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= Date: Sun, 8 Feb 2026 13:43:41 +0100 Subject: [PATCH 1/4] system: add kanidm PAM/NSS client module Add homelab.kanidm.enable option for central authentication via Kanidm. The module configures: - PAM/NSS integration with kanidm-unixd - Client connection to auth.home.2rjus.net - Login authorization for ssh-users group Enable on testvm01-03 for testing. Co-Authored-By: Claude Opus 4.5 --- docs/user-management.md | 164 +++++++++++++++++++++++++++++++ hosts/testvm01/configuration.nix | 3 + hosts/testvm02/configuration.nix | 3 + hosts/testvm03/configuration.nix | 3 + system/default.nix | 1 + system/kanidm-client.nix | 42 ++++++++ 6 files changed, 216 insertions(+) create mode 100644 docs/user-management.md create mode 100644 system/kanidm-client.nix diff --git a/docs/user-management.md b/docs/user-management.md new file mode 100644 index 0000000..b45411c --- /dev/null +++ b/docs/user-management.md @@ -0,0 +1,164 @@ +# User Management with Kanidm + +Central authentication for the homelab using Kanidm. + +## Overview + +- **Server**: kanidm01.home.2rjus.net (auth.home.2rjus.net) +- **WebUI**: https://auth.home.2rjus.net +- **LDAPS**: port 636 + +## CLI Setup + +The `kanidm` CLI is available in the devshell: + +```bash +nix develop + +# Login as idm_admin +kanidm login --name idm_admin --url https://auth.home.2rjus.net +``` + +## User Management + +### Creating Users + +Users are provisioned declaratively in `services/kanidm/default.nix`: + +```nix +services.kanidm.provision.persons.username = { + displayName = "Display Name"; + groups = [ "admins" "users" "ssh-users" ]; +}; +``` + +### Enabling POSIX for Users + +For PAM/NSS integration, users need POSIX attributes and a UNIX password: + +```bash +# Check if user has POSIX enabled +kanidm person get + +# Set UNIX password (required for SSH login) +kanidm person posix set-password +``` + +## Group Management + +### Creating Groups + +Groups are provisioned declaratively: + +```nix +services.kanidm.provision.groups = { + admins = { }; + users = { }; + ssh-users = { }; +}; +``` + +### Enabling POSIX for Groups + +Groups must have POSIX enabled to be resolved via NSS: + +```bash +# Enable POSIX on a group with a specific GID +kanidm group posix set --gidnumber + +# Example: enable ssh-users group +kanidm group posix set ssh-users --gidnumber 68000 +``` + +### UID/GID Allocation + +| Range | Purpose | +|-------|---------| +| 65,536 - 67,999 | Users | +| 68,000 - 69,999 | Groups | + +## PAM/NSS Client Configuration + +Enable central authentication on a host: + +```nix +homelab.kanidm.enable = true; +``` + +This configures: +- `services.kanidm.enablePam = true` +- Client connection to auth.home.2rjus.net +- Login authorization for `ssh-users` group + +### Options + +```nix +homelab.kanidm = { + enable = true; + server = "https://auth.home.2rjus.net"; # default + allowedLoginGroups = [ "ssh-users" ]; # default +}; +``` + +## Testing + +### Verify NSS Resolution + +```bash +# Check user resolution +getent passwd + +# Check group resolution +getent group +``` + +### Test SSH Login + +```bash +ssh @.home.2rjus.net +``` + +## Troubleshooting + +### "PAM user mismatch" error + +SSH fails with "fatal: PAM user mismatch" in logs. This happens when Kanidm returns +usernames in SPN format (`torjus@home.2rjus.net`) but SSH expects short names (`torjus`). + +**Solution**: Configure `uid_attr_map = "name"` in unixSettings (already set in our module). + +Check current format: +```bash +getent passwd torjus +# Should show: torjus:x:65536:... +# NOT: torjus@home.2rjus.net:x:65536:... +``` + +### User resolves but SSH fails immediately + +The user's login group (e.g., `ssh-users`) likely doesn't have POSIX enabled: + +```bash +# Check if group has POSIX +getent group ssh-users + +# If empty, enable POSIX on the server +kanidm group posix set ssh-users --gidnumber 68000 +``` + +### User doesn't resolve via getent + +1. Check kanidm-unixd service is running: + ```bash + systemctl status kanidm-unixd + ``` + +2. Check client can reach server: + ```bash + curl -s https://auth.home.2rjus.net/status + ``` + +3. Check user has POSIX enabled on server: + ```bash + kanidm person get + ``` diff --git a/hosts/testvm01/configuration.nix b/hosts/testvm01/configuration.nix index ee93d4a..0fe1fa5 100644 --- a/hosts/testvm01/configuration.nix +++ b/hosts/testvm01/configuration.nix @@ -25,6 +25,9 @@ # Enable remote deployment via NATS homelab.deploy.enable = true; + # Enable Kanidm PAM/NSS for central authentication + homelab.kanidm.enable = true; + nixpkgs.config.allowUnfree = true; boot.loader.grub.enable = true; boot.loader.grub.device = "/dev/vda"; diff --git a/hosts/testvm02/configuration.nix b/hosts/testvm02/configuration.nix index 5e6f11b..d63e5b5 100644 --- a/hosts/testvm02/configuration.nix +++ b/hosts/testvm02/configuration.nix @@ -25,6 +25,9 @@ # Enable remote deployment via NATS homelab.deploy.enable = true; + # Enable Kanidm PAM/NSS for central authentication + homelab.kanidm.enable = true; + nixpkgs.config.allowUnfree = true; boot.loader.grub.enable = true; boot.loader.grub.device = "/dev/vda"; diff --git a/hosts/testvm03/configuration.nix b/hosts/testvm03/configuration.nix index 6fd9b48..cd0789d 100644 --- a/hosts/testvm03/configuration.nix +++ b/hosts/testvm03/configuration.nix @@ -25,6 +25,9 @@ # Enable remote deployment via NATS homelab.deploy.enable = true; + # Enable Kanidm PAM/NSS for central authentication + homelab.kanidm.enable = true; + nixpkgs.config.allowUnfree = true; boot.loader.grub.enable = true; boot.loader.grub.device = "/dev/vda"; diff --git a/system/default.nix b/system/default.nix index 9ba5d06..4ab14ac 100644 --- a/system/default.nix +++ b/system/default.nix @@ -4,6 +4,7 @@ ./acme.nix ./autoupgrade.nix ./homelab-deploy.nix + ./kanidm-client.nix ./monitoring ./motd.nix ./packages.nix diff --git a/system/kanidm-client.nix b/system/kanidm-client.nix new file mode 100644 index 0000000..c720aa7 --- /dev/null +++ b/system/kanidm-client.nix @@ -0,0 +1,42 @@ +{ lib, config, pkgs, ... }: +let + cfg = config.homelab.kanidm; +in +{ + options.homelab.kanidm = { + enable = lib.mkEnableOption "Kanidm PAM/NSS client for central authentication"; + + server = lib.mkOption { + type = lib.types.str; + default = "https://auth.home.2rjus.net"; + description = "URI of the Kanidm server"; + }; + + allowedLoginGroups = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ "ssh-users" ]; + description = "Groups allowed to log in via PAM"; + }; + }; + + config = lib.mkIf cfg.enable { + services.kanidm = { + package = pkgs.kanidm_1_8; + enablePam = true; + + clientSettings = { + uri = cfg.server; + }; + + unixSettings = { + pam_allowed_login_groups = cfg.allowedLoginGroups; + # Use short names (torjus) instead of SPN format (torjus@home.2rjus.net) + # This prevents "PAM user mismatch" errors with SSH + uid_attr_map = "name"; + gid_attr_map = "name"; + # Create symlink /home/torjus -> /home/torjus@home.2rjus.net + home_alias = "name"; + }; + }; + }; +} From 54b6e374209a5bae11183471bf159626defd7f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= Date: Sun, 8 Feb 2026 13:46:53 +0100 Subject: [PATCH 2/4] flake: add kanidm to devshell Add kanidm_1_8 CLI for administering the Kanidm server. Co-Authored-By: Claude Opus 4.5 --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index e19feb7..375da28 100644 --- a/flake.nix +++ b/flake.nix @@ -207,6 +207,7 @@ pkgs.ansible pkgs.opentofu pkgs.openbao + pkgs.kanidm_1_8 (pkgs.callPackage ./scripts/create-host { }) homelab-deploy.packages.${pkgs.system}.default ]; From b31c64f1b9ec932766b70c5514b20e03a1a28b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= Date: Sun, 8 Feb 2026 14:55:19 +0100 Subject: [PATCH 3/4] kanidm: remove declarative user provisioning Keep base groups (admins, users, ssh-users) provisioned declaratively but manage regular users via the kanidm CLI. This allows setting POSIX attributes and passwords in a single workflow. Co-Authored-By: Claude Opus 4.5 --- services/kanidm/default.nix | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/services/kanidm/default.nix b/services/kanidm/default.nix index c245079..c7baaa1 100644 --- a/services/kanidm/default.nix +++ b/services/kanidm/default.nix @@ -17,7 +17,8 @@ }; }; - # Provisioning - initial users/groups + # Provision base groups only - users are managed via CLI + # See docs/user-management.md for details provision = { enable = true; idmAdminPasswordFile = config.vault.secrets.kanidm-idm-admin.outputDir; @@ -28,10 +29,7 @@ ssh-users = { }; }; - persons.torjus = { - displayName = "Torjus"; - groups = [ "admins" "users" "ssh-users" ]; - }; + # Regular users (persons) are managed imperatively via kanidm CLI }; }; @@ -46,7 +44,7 @@ extraDomainNames = [ "${config.networking.hostName}.home.2rjus.net" ]; }; - # Vault secret for idm_admin password + # Vault secret for idm_admin password (used for provisioning) vault.secrets.kanidm-idm-admin = { secretPath = "kanidm/idm-admin-password"; extractKey = "password"; From 9ed09c9a9c73654585891e4e3bff6c70b5e55f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= Date: Sun, 8 Feb 2026 14:27:15 +0100 Subject: [PATCH 4/4] docs: add user-management documentation - CLI workflows for creating users and groups - Troubleshooting guide (nscd, cache invalidation) - Home directory behavior (UUID-based with symlinks) - Update auth-system-replacement plan with progress Co-Authored-By: Claude Opus 4.5 --- docs/plans/auth-system-replacement.md | 52 ++++++-- docs/user-management.md | 179 ++++++++++++++++++++------ 2 files changed, 179 insertions(+), 52 deletions(-) diff --git a/docs/plans/auth-system-replacement.md b/docs/plans/auth-system-replacement.md index 569e683..dcd97c7 100644 --- a/docs/plans/auth-system-replacement.md +++ b/docs/plans/auth-system-replacement.md @@ -66,9 +66,9 @@ This future migration path is a strong argument for Kanidm over LDAP-only soluti - Vault integration for idm_admin password - LDAPS on port 636 -2. **Configure declarative provisioning** ✅ - - Groups: `admins`, `users`, `ssh-users` - - User: `torjus` (member of all groups) +2. **Configure provisioning** ✅ + - Groups provisioned declaratively: `admins`, `users`, `ssh-users` + - Users managed imperatively via CLI (allows setting POSIX passwords in one step) - POSIX attributes enabled (UID/GID range 65,536-69,999) 3. **Test NAS integration** (in progress) @@ -80,14 +80,16 @@ This future migration path is a strong argument for Kanidm over LDAP-only soluti - Grafana - Other services as needed -5. **Create client module** in `system/` for PAM/NSS - - Enable on all hosts that need central auth - - Configure trusted CA +5. **Create client module** in `system/` for PAM/NSS ✅ + - Module: `system/kanidm-client.nix` + - `homelab.kanidm.enable = true` enables PAM/NSS + - Short usernames (not SPN format) + - Home directory symlinks via `home_alias` + - Enabled on test tier: testvm01, testvm02, testvm03 -6. **Documentation** - - User management procedures - - Adding new OAuth2 clients - - Troubleshooting PAM/NSS issues +6. **Documentation** ✅ + - `docs/user-management.md` - CLI workflows, troubleshooting + - User/group creation procedures verified working ## Progress @@ -106,14 +108,37 @@ This future migration path is a strong argument for Kanidm over LDAP-only soluti - Prometheus monitoring scrape target configured **Provisioned entities:** -- Groups: `admins`, `users`, `ssh-users` -- User: `torjus` (member of all groups, POSIX enabled with GID 65536) +- Groups: `admins`, `users`, `ssh-users` (declarative) +- Users managed via CLI (imperative) **Verified working:** - WebUI login with idm_admin - LDAP bind and search with POSIX-enabled user - LDAPS with valid internal CA certificate +### Completed (2026-02-08) - PAM/NSS Client + +**Client module deployed (`system/kanidm-client.nix`):** +- `homelab.kanidm.enable = true` enables PAM/NSS integration +- Connects to auth.home.2rjus.net +- Short usernames (`torjus` instead of `torjus@home.2rjus.net`) +- Home directory symlinks (`/home/torjus` → UUID-based dir) +- Login restricted to `ssh-users` group + +**Enabled on test tier:** +- testvm01, testvm02, testvm03 + +**Verified working:** +- User/group resolution via `getent` +- SSH login with Kanidm unix passwords +- Home directory creation with symlinks +- Imperative user/group creation via CLI + +**Documentation:** +- `docs/user-management.md` with full CLI workflows +- Password requirements (min 10 chars) +- Troubleshooting guide (nscd, cache invalidation) + ### UID/GID Range (Resolved) **Range: 65,536 - 69,999** (manually allocated) @@ -128,10 +153,9 @@ Rationale: ### Next Steps -1. Deploy to monitoring01 to enable Prometheus scraping +1. Enable PAM/NSS on production hosts (after test tier validation) 2. Configure TrueNAS LDAP client for NAS integration testing 3. Add OAuth2 clients (Grafana first) -4. Create PAM/NSS client module for other hosts ## References diff --git a/docs/user-management.md b/docs/user-management.md index b45411c..a3ff69a 100644 --- a/docs/user-management.md +++ b/docs/user-management.md @@ -21,61 +21,113 @@ kanidm login --name idm_admin --url https://auth.home.2rjus.net ## User Management -### Creating Users +POSIX users are managed imperatively via the `kanidm` CLI. This allows setting +all attributes (including UNIX password) in one workflow. -Users are provisioned declaratively in `services/kanidm/default.nix`: - -```nix -services.kanidm.provision.persons.username = { - displayName = "Display Name"; - groups = [ "admins" "users" "ssh-users" ]; -}; -``` - -### Enabling POSIX for Users - -For PAM/NSS integration, users need POSIX attributes and a UNIX password: +### Creating a POSIX User ```bash -# Check if user has POSIX enabled -kanidm person get +# Create the person +kanidm person create "" -# Set UNIX password (required for SSH login) +# Add to groups +kanidm group add-members ssh-users + +# Enable POSIX (UID is auto-assigned) +kanidm person posix set + +# Set UNIX password (required for SSH login, min 10 characters) kanidm person posix set-password + +# Optionally set login shell +kanidm person posix set --shell /bin/zsh +``` + +### Example: Full User Creation + +```bash +kanidm person create testuser "Test User" +kanidm group add-members ssh-users testuser +kanidm person posix set testuser +kanidm person posix set-password testuser +kanidm person get testuser +``` + +After creation, verify on a client host: +```bash +getent passwd testuser +ssh testuser@testvm01.home.2rjus.net +``` + +### Viewing User Details + +```bash +kanidm person get +``` + +### Removing a User + +```bash +kanidm person delete ``` ## Group Management -### Creating Groups +Groups for POSIX access are also managed via CLI. -Groups are provisioned declaratively: - -```nix -services.kanidm.provision.groups = { - admins = { }; - users = { }; - ssh-users = { }; -}; -``` - -### Enabling POSIX for Groups - -Groups must have POSIX enabled to be resolved via NSS: +### Creating a POSIX Group ```bash -# Enable POSIX on a group with a specific GID -kanidm group posix set --gidnumber +# Create the group +kanidm group create -# Example: enable ssh-users group -kanidm group posix set ssh-users --gidnumber 68000 +# Enable POSIX with a specific GID +kanidm group posix set --gidnumber ``` +### Adding Members + +```bash +kanidm group add-members +``` + +### Viewing Group Details + +```bash +kanidm group get +kanidm group list-members +``` + +### Example: Full Group Creation + +```bash +kanidm group create testgroup +kanidm group posix set testgroup --gidnumber 68010 +kanidm group add-members testgroup testuser +kanidm group get testgroup +``` + +After creation, verify on a client host: +```bash +getent group testgroup +``` + +### Current Groups + +| Group | GID | Purpose | +|-------|-----|---------| +| ssh-users | 68000 | SSH login access | +| admins | 68001 | Administrative access | +| users | 68002 | General users | + ### UID/GID Allocation +Kanidm auto-assigns UIDs/GIDs from its configured range. For manually assigned GIDs: + | Range | Purpose | |-------|---------| -| 65,536 - 67,999 | Users | -| 68,000 - 69,999 | Groups | +| 65,536+ | Users (auto-assigned) | +| 68,000 - 68,999 | Groups (manually assigned) | ## PAM/NSS Client Configuration @@ -89,6 +141,12 @@ This configures: - `services.kanidm.enablePam = true` - Client connection to auth.home.2rjus.net - Login authorization for `ssh-users` group +- Short usernames (`torjus` instead of `torjus@home.2rjus.net`) +- Home directory symlinks (`/home/torjus` → UUID-based directory) + +### Enabled Hosts + +- testvm01, testvm02, testvm03 (test tier) ### Options @@ -100,6 +158,17 @@ homelab.kanidm = { }; ``` +### Home Directories + +Home directories use UUID-based paths for stability (so renaming a user doesn't +require moving their home directory). Symlinks provide convenient access: + +``` +/home/torjus -> /home/e4f4c56c-4aee-4c20-846f-90cb69807733 +``` + +The symlinks are created by `kanidm-unixd-tasks` on first login. + ## Testing ### Verify NSS Resolution @@ -153,12 +222,46 @@ kanidm group posix set ssh-users --gidnumber 68000 systemctl status kanidm-unixd ``` -2. Check client can reach server: +2. Check unixd can reach server: + ```bash + kanidm-unix status + # Should show: system: online, Kanidm: online + ``` + +3. Check client can reach server: ```bash curl -s https://auth.home.2rjus.net/status ``` -3. Check user has POSIX enabled on server: +4. Check user has POSIX enabled on server: ```bash kanidm person get ``` + +5. Restart nscd to clear stale cache: + ```bash + systemctl restart nscd + ``` + +6. Invalidate kanidm cache: + ```bash + kanidm-unix cache-invalidate + ``` + +### Changes not taking effect after deployment + +NixOS uses nsncd (a Rust reimplementation of nscd) for NSS caching. After deploying +kanidm-unixd config changes, you may need to restart both services: + +```bash +systemctl restart kanidm-unixd +systemctl restart nscd +``` + +### Test PAM authentication directly + +Use the kanidm-unix CLI to test PAM auth without SSH: + +```bash +kanidm-unix auth-test --name +```