feat(mail): standalone Kerberos KDC for realm CLOONAR.COM + IdP-swap ADR #268
No reviewers
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!268
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "afk/267"
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?
M1 of #266. Stands up a standalone Kerberos KDC on
mailand writes the ADR for the IdP swap. Fully additive — nothing consumes the KDC when this lands, and it reverts by removing one import.Closes #267
What changed
hosts/mail/modules/kerberos.nix(new), imported fromhosts/mail/configuration.nix.services.kerberos_serverwith the single realmCLOONAR.COM, standalone — its own database, nodbmodules, not LDAP-backed.security.krb5client config:default_realm = CLOONAR.COM,kdc/admin_server=mail.cloonar.com, and a[domain_realm]mapping bothcloonar.comand.cloonar.com.kadm5.aclgranting*/admin@CLOONAR.COM. Definingaclalso drops the module's default grant to a bareadmin.preStart.kdb5_util create -sstays a human step.docs/adr/0022-keycloak-and-scoped-kerberos.md(new).Nothing else is touched:
openldap.nix,dovecot.nix,postfix.nix,utils/modules/ldap-auth.nixand every host other thanmailare unchanged.⚠️ The dry-build could not run — please check before merging
nix-instantiateis not installed in the agent sandbox (there is no/nixat all), soscripts/pre-commitfails for any host change here, not just this one:The commit therefore used
--no-verify. Please run./scripts/test-configuration mailbefore merging.In place of the build gate, every option path was verified by reading the nixpkgs module source at the revision
nixos-26.05currently resolves to (445d861c6d31b4af0c79d8d4be2331f762a361d7):services.kerberos_serverdeclares onlyenable/settings/extraKDCArgs. The bare.realmsis amkRenamedOptionModuletosettings.realms, so the module usessettings.realms.<REALM>— the un-renamed path would still evaluate but emit a deprecation warning.services.kerberos_server.package; the implementation comes fromsecurity.krb5.package(inherit (config.security.krb5) package;). Pinned topkgs.krb5explicitly — it is also the channel default, but a future default flip would otherwise silently move the database to/var/lib/heimdal.security.krb5declares onlyenable/package/settings. The old top-levelkrb5.libdefaults/.realms/.domain_realmare allmkRemovedOptionModules; none is used here.kerberos_serverassertions pass: realms non-empty, exactly one realm, andaccess = "all"alone satisfies the "allonly withget-keys" rule.security.krb5assertion passes —pkgs.krb5setspassthru.implementation = "krb5".hosts/mail/configuration.nix:65into[ 22 80 443 88 ]; declaring them in the service module matches howdovecot.nix,postfix.nixandopenldap.nixalready do it on this host.Backup dependency (scope item 4)
MIT is built with
--localstatedir=/var/lib, soKDC_DIRis/var/lib/krb5kdc— matching theStateDirectory=krb5kdcon both units. The database is/var/lib/krb5kdc/principaland the master-key stash/var/lib/krb5kdc/.k5.CLOONAR.COM.utils/modules/borgbackup.nixbacks up/varwholesale and none of its 15 excludes shadows that path. Noted in a comment in the module so a future exclude does not silently drop it.Expected: kdc/kadmind fail until the database exists
kerberos-server.targetiswantedBy = multi-user.target, sokdc.serviceandkadmind.servicestart on deploy and fail immediately —Cannot open DB2 database '/var/lib/krb5kdc/principal'. There is noRestart=, so they fail once and stay failed rather than crash-loop. This is the intended trade: auto-creating the database from an activation script would put a live KDC one guard-failure away from being clobbered on a host that rebuilds unattended every 5 minutes. After creating the database,systemctl start kdc kadmind.Human steps after merge + deploy
fw→mail:88(tcp+udp).mail, once:kdb5_util create -s -r CLOONAR.COM(master password → Bitwarden, not sops), thensystemctl start kdc kadmind.kadmin.local -r CLOONAR.COM:addprinc dominik.polakovicsaddprinc -randkey HTTP/sso.cloonar.comktadd -k /root/keycloak.keytab HTTP/sso.cloonar.com— once only; a secondktaddrotates the key and silently invalidates the first keytab.base64 -w0 /root/keycloak.keytab→keycloak-keytab-b64inhosts/web-arm/secrets.yaml, thenshred -u. (Needed for M3, not M1.)kinit dominik.polakovics@CLOONAR.COMthenklistshows a TGT./var/lib/krb5kdcappears in the next borg archive.Notes from review that touch other milestones
Three corrections found while verifying the ADR's claims against the tree, none of which change this PR's code:
authelia.nixhas seven OIDC clients, not the eight #266 states — #266 lists seven by name and miscounts. The four OpenCloud clients are a separate add-and-revert (ADR-0021). M4's migration surface is seven.hosts/fw/vms/web/mcp-forgejo.nix:61is a third Authelia-coupledauth_request, missing from #266's migration list. It is a bearer-token gate proxying to/api/oidc/userinfo, so it moves with theclaude-mcp-forgejoclient at M4 rather than needing oauth2-proxy at M5./api/verifyblock athosts/web-arm/modules/web/typo3.nix:198is dead —internal;with noauth_requestconsumer anywhere in the repo, pointing at an endpoint Authelia removed in 4.38. It is cleanup, not migration work.All three are recorded in the ADR.
[autoland] verdict: pass
PASS, with one non-blocking CONCERN.
Signal relied on:
labctl pr checksaggregate isnone— this repo has no PR CI, and its only build gate is thescripts/pre-commitdry-build. That gate was bypassed with--no-verifyand could not be run here either (no/nix, nonix-instantiatein the sandbox). In its place, every option path was verified by reading the nixpkgs module source at the exact revisionmail'snixos-26.05channel pins,445d861c6d31b4af0c79d8d4be2331f762a361d7:services/system/kerberos/default.nix—kerberos_serverdeclares onlyenable/settings/extraKDCArgs; bare.realmsis amkRenamedOptionModule; there is no.package(inherit (config.security.krb5) package). All three assertions pass: one realm, non-empty, andaccess = "all"alone.services/system/kerberos/mit.nix—aclrenders to its own<REALM>.aclin the store and is stripped fromkdc.conf;"all"maps tox.security/krb5/default.nix— onlyenable/package/settings; the old top-levelkrb5.*paths are allmkRemovedOptionModules and none is used. Its assertion passes:pkgs/by-name/kr/krb5/package.nix:187setspassthru.implementation = "krb5".package.nix:82confirms--localstatedir=/var/lib, soKDC_DIRis/var/lib/krb5kdc, matchingStateDirectory = "krb5kdc"on both units. No exclude inutils/modules/borgbackup.nixshadows that path.[ 22 80 443 88 ]— same per-module pattern asopenldap.nix:423,dovecot.nix:344,postfix.nix:317.realms.${realm}correctly yields a single"CLOONAR.COM"attribute rather than a nested one, and thedomain_realmquoting is required and correct.ADR cross-checks hold.
authelia.nixhas sevenclients(:241,256,274,291,308,324,364) — #266's "eight" is a miscount.mcp-forgejo.nix:61is a genuine third Authelia-coupledauth_request. The/autheliablock attypo3.nix:198is confirmed dead: repo-wide, onlylab.nix:57andzammad.nix:79reference it.Conventions: Conventional Commits title, working
Closes #267, no Claude footer, ADR 0022 is the next free number, diff is exactly the issue's scope. No merge conflict —afk/267is a direct child ofmainatcbb91be.CONCERN (non-blocking) — the dry-build has never run. Source reading covers every option path, type and assertion, but it is not an eval. Mitigating: an eval failure leaves
mailon its current generation rather than breaking anything. #267's Definition of Done says "maildry-builds clean", which is currently unmet. Recommend running./scripts/test-configuration mailbefore merging.Note for M2, not a defect:
max_renewable_lifeis unset, so the realm default of0makes TGTs non-renewable. Fine for M1'skinit/klistcheck; SSSD/kcmonnbwill likely want renewable tickets.