fix(mail): open kpasswd (464) so password changes reach the KDC #305

Merged
dominik.polakovics merged 1 commit from lab/20260808-1423 into main 2026-08-08 15:27:39 +02:00

Found while running the M1 verification spikes from #301 (spike 2, the SDDM expired-password test).

What is broken

kadmind on mail listens on 464 (tcp+udp) and 749, but nixos-fw only allowed 88. SSSD on nb runs chpass_provider = krb5 and, with no krb5_kpasswd set, assumes the change-password service lives on the KDC — so every password change was aimed at a port that drops packets.

The failure is silent. SDDM renders the CHANGE_EXPIRED_AUTHTOK prompt correctly, accepts a new password, reports no error, and logs the user in. Meanwhile nothing reaches the KDC: the principal keeps REQUIRES_PWCHANGE and its old key. The login succeeds from SSSD's offline cache, since krb5_store_password_if_offline = true (hosts/nb/modules/ldap-login.nix:52).

Under ADR-0023, where Kerberos becomes the only credential for the identity tenant, that is a user who believes they have rotated a compromised password and has not.

Evidence

kpasswd from nb:

$ kpasswd dominik.polakovics
Password for dominik.polakovics@CLOONAR.COM:
Enter new password:
Enter it again:
kpasswd: Cannot contact any KDC for requested realm changing password

kadmind is listening fine on mail:

udp UNCONN 0.0.0.0:464   users:(("kadmind",pid=156678,fd=7))
tcp LISTEN 0.0.0.0:464   users:(("kadmind",pid=156678,fd=9))
tcp LISTEN 0.0.0.0:749   users:(("kadmind",pid=156678,fd=11))

And after a full greeter-driven password change, getprinc still showed Attributes: REQUIRES_PWCHANGE with Last password change unchanged from the admin cpw that set up the test.

The corresponding SSSD journal is two kpasswd attempts timing out and being SIGKILLed, then the backend going offline:

child timed out! ... child was terminated by signal [9]
No available servers for service 'KERBEROS'
SSSD is offline

The change

Opens 464 tcp+udp, mirroring how 88 is already handled — source restriction stays with the Hetzner firewall rather than nixos-fw, which has no LAN or WireGuard interface on this host to scope against. 749 stays closed, per ADR-0023 decision 10.

Caveats for the reviewer

  • Not dry-built. Nix is unavailable in this lab worktree (nix-instantiate not found), so scripts/test-configuration mail could not run and the commit used --no-verify. The diff is a two-element list literal, but it has not been evaluated.
  • The blocking layer was not fully isolated. iptables -S nixos-fw and nft list ruleset both returned empty on mail, which is not what a live nixos-fw ruleset should look like. The behaviour is unambiguous and this change is required by ADR-0023 decision 10 regardless, but if kpasswd still fails after deploy, the Hetzner firewall is the remaining suspect.
  • hosts/mail/modules/kerberos.nix:5 still describes the old Hetzner boundary ("restricts port 88 to fw"). #299 M2 already flags it as stale; left alone here rather than rewriting it to a posture I have not verified.

Follow-ups this surfaced (not in this PR)

  • Spike 2 splits into two results: SDDM can render the prompt (answered, contingency dead), but the admin-reset flow is untestable until this lands. It was run ahead of its own prerequisite.
  • pam_sss in the password stack has no use_authtok (/etc/pam.d/login), while pam_gnome_keyring below it does. pam_unix runs first, prompts for new+retype, and fails because identity-tenant users have no local password by design — so the user is asked for the current password twice and a new one four times.
  • The principal carries Maximum ticket life: 1 day and Maximum renewable life: 0, against ADR-0023 decision 9's max_life = 10h / max_renewable_life = 7d. kdc.conf realm defaults do not retroactively apply, so M6 enrolment has to set these per principal.

Refs #301, #299.

Found while running the M1 verification spikes from #301 (spike 2, the SDDM expired-password test). ## What is broken `kadmind` on `mail` listens on 464 (tcp+udp) and 749, but `nixos-fw` only allowed 88. SSSD on `nb` runs `chpass_provider = krb5` and, with no `krb5_kpasswd` set, assumes the change-password service lives on the KDC — so every password change was aimed at a port that drops packets. **The failure is silent.** SDDM renders the `CHANGE_EXPIRED_AUTHTOK` prompt correctly, accepts a new password, reports no error, and logs the user in. Meanwhile nothing reaches the KDC: the principal keeps `REQUIRES_PWCHANGE` and its old key. The login succeeds from SSSD's offline cache, since `krb5_store_password_if_offline = true` (`hosts/nb/modules/ldap-login.nix:52`). Under ADR-0023, where Kerberos becomes the only credential for the identity tenant, that is a user who believes they have rotated a compromised password and has not. ## Evidence `kpasswd` from `nb`: ``` $ kpasswd dominik.polakovics Password for dominik.polakovics@CLOONAR.COM: Enter new password: Enter it again: kpasswd: Cannot contact any KDC for requested realm changing password ``` `kadmind` is listening fine on `mail`: ``` udp UNCONN 0.0.0.0:464 users:(("kadmind",pid=156678,fd=7)) tcp LISTEN 0.0.0.0:464 users:(("kadmind",pid=156678,fd=9)) tcp LISTEN 0.0.0.0:749 users:(("kadmind",pid=156678,fd=11)) ``` And after a full greeter-driven password change, `getprinc` still showed `Attributes: REQUIRES_PWCHANGE` with `Last password change` unchanged from the admin `cpw` that set up the test. The corresponding SSSD journal is two kpasswd attempts timing out and being SIGKILLed, then the backend going offline: ``` child timed out! ... child was terminated by signal [9] No available servers for service 'KERBEROS' SSSD is offline ``` ## The change Opens 464 tcp+udp, mirroring how 88 is already handled — source restriction stays with the Hetzner firewall rather than nixos-fw, which has no LAN or WireGuard interface on this host to scope against. 749 stays closed, per ADR-0023 decision 10. ## Caveats for the reviewer - **Not dry-built.** Nix is unavailable in this lab worktree (`nix-instantiate` not found), so `scripts/test-configuration mail` could not run and the commit used `--no-verify`. The diff is a two-element list literal, but it has not been evaluated. - **The blocking layer was not fully isolated.** `iptables -S nixos-fw` and `nft list ruleset` both returned empty on `mail`, which is not what a live nixos-fw ruleset should look like. The behaviour is unambiguous and this change is required by ADR-0023 decision 10 regardless, but if `kpasswd` still fails after deploy, the Hetzner firewall is the remaining suspect. - `hosts/mail/modules/kerberos.nix:5` still describes the old Hetzner boundary ("restricts port 88 to fw"). #299 M2 already flags it as stale; left alone here rather than rewriting it to a posture I have not verified. ## Follow-ups this surfaced (not in this PR) - Spike 2 splits into two results: SDDM **can** render the prompt (answered, contingency dead), but the admin-reset flow is untestable until this lands. It was run ahead of its own prerequisite. - `pam_sss` in the `password` stack has no `use_authtok` (`/etc/pam.d/login`), while `pam_gnome_keyring` below it does. `pam_unix` runs first, prompts for new+retype, and fails because identity-tenant users have no local password by design — so the user is asked for the current password twice and a new one four times. - The principal carries `Maximum ticket life: 1 day` and `Maximum renewable life: 0`, against ADR-0023 decision 9's `max_life = 10h` / `max_renewable_life = 7d`. `kdc.conf` realm defaults do not retroactively apply, so M6 enrolment has to set these per principal. Refs #301, #299.
kadmind listens on 464 (tcp+udp) and 749, but nixos-fw only allowed 88, so
SSSD's chpass_provider = krb5 on nb could never reach the change-password
service. The failure is silent: the greeter renders the expired-password
prompt, accepts a new password, and reports nothing, while the principal
keeps REQUIRES_PWCHANGE and the old key. Verified with `kpasswd` from nb —
"Cannot contact any KDC for requested realm changing password" — against
kadmind confirmed listening on 0.0.0.0:464.

749 stays closed per ADR-0023 decision 10.
dominik.polakovics deleted branch lab/20260808-1423 2026-08-08 15:27:39 +02:00
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
Cloonar/nixos!305
No description provided.