From 8f30c323bc325fe18f02a8a17a001ed8cc130356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98ystein=20Tveit?= Date: Sat, 6 Jul 2024 13:08:05 +0200 Subject: [PATCH] WIP: set up heimdal-openldap-sasl stack --- hosts/dagali/TODO.md | 63 ++++++++++++++ hosts/dagali/configuration.nix | 7 ++ hosts/dagali/services/cyrus-sasl.nix | 21 +++++ hosts/dagali/services/heimdal.nix | 80 ++++++++++++++++++ hosts/dagali/services/openldap.nix | 121 +++++++++++++++++++++++++++ 5 files changed, 292 insertions(+) create mode 100644 hosts/dagali/TODO.md create mode 100644 hosts/dagali/services/cyrus-sasl.nix create mode 100644 hosts/dagali/services/heimdal.nix create mode 100644 hosts/dagali/services/openldap.nix diff --git a/hosts/dagali/TODO.md b/hosts/dagali/TODO.md new file mode 100644 index 0000000..f134ca6 --- /dev/null +++ b/hosts/dagali/TODO.md @@ -0,0 +1,63 @@ +# Tracking document for new PVV kerberos auth stack + +![Bensinstasjon på heimdal](https://bydelsnytt.no/wp-content/uploads/2022/08/esso_heimdal003.jpg) + +
+ Bensinstasjon på heimdal +
+ +### TODO: + +- [ ] setup heimdal + - [x] ensure running with systemd + - [x] compile smbk5pwd (part of openldap) + - [ ] set `modify -a -disallow-all-tix,requires-pre-auth default` declaratively + - [ ] fully initialize PVV.NTNU.NO + - [x] `kadmin -l init PVV.NTNU.NO` + - [x] add oysteikt/admin@PVV.NTNU.NO principal + - [x] add oysteikt@PVV.NTNU.NO principal + - [ ] add krbtgt@PVV.NTNU.NO principal? + - why is this needed, and where is it documented? + - `kadmin check` seems to work under sudo? + - Fix FQDN: https://github.com/NixOS/nixpkgs/issues/94011 + https://github.com/NixOS/nixpkgs/issues/261269 + +- [ ] setup cyrus sasl + - [x] ensure running with systemd + - [x] verify GSSAPI support plugin is installed + - `nix-shell -p cyrus_sasl --command pluginviewer` + - [x] create "host/localhost@PVV.NTNU.NO" and export to keytab + - [x] verify cyrus sasl is able to talk to heimdal + - `sudo testsaslauthd -u oysteikt -p ` + - [ ] provide ldap principal to cyrus sasl through keytab + +- [ ] setup openldap + - [x] ensure running with systemd + - [ ] verify openldap is able to talk to cyrus sasl + - [ ] create user for oysteikt in openldap + - [ ] authenticate openldap login through sasl + - does this require creating an ldap user? + +- [ ] fix smbk5pwd integration + - [x] add smbk5pwd schemas to openldap + - [x] create openldap db for smbk5pwd with overlays + - [ ] test to ensure that user sync is working + - [ ] test as user source (replace passwd) + - [ ] test as PAM auth source + - [ ] test as auth source for 3rd party appliation + +- [ ] Set up ldap administration panel + - Doesn't seem like there are many good ones out there. Maybe phpLDAPAdmin? + +- [ ] Set up kerberos SRV DNS entry + +### Information and URLS + +- OpenLDAP SASL: https://www.openldap.org/doc/admin24/sasl.html +- Use a keytab: https://kb.iu.edu/d/aumh +- 2 ways for openldap to auth: https://security.stackexchange.com/questions/65093/how-to-test-ldap-that-authenticates-with-kerberos +- Cyrus guide OpenLDAP + SASL + GSSAPI: https://www.cyrusimap.org/sasl/sasl/faqs/openldap-sasl-gssapi.html +- Configuring GSSAPI and Cyrus SASL: https://web.mit.edu/darwin/src/modules/passwordserver_sasl/cyrus_sasl/doc/gssapi.html +- PVV Kerberos docs: https://wiki.pvv.ntnu.no/wiki/Drift/Kerberos +- OpenLDAP smbk5pwd source: https://git.openldap.org/nivanova/openldap/-/tree/master/contrib/slapd-modules/smbk5pwd +- saslauthd(8): https://linux.die.net/man/8/saslauthd diff --git a/hosts/dagali/configuration.nix b/hosts/dagali/configuration.nix index 499d3b6..5c64273 100644 --- a/hosts/dagali/configuration.nix +++ b/hosts/dagali/configuration.nix @@ -5,6 +5,10 @@ ./hardware-configuration.nix ../../base.nix ../../misc/metrics-exporters.nix + + ./services/heimdal.nix + ./services/openldap.nix + ./services/cyrus-sasl.nix ]; # buskerud does not support efi? @@ -13,6 +17,9 @@ boot.loader.grub.enable = true; boot.loader.grub.device = "/dev/sda"; + # resolved messes up FQDN coming from nscd + services.resolved.enable = false; + networking.hostName = "dagali"; networking.search = [ "pvv.ntnu.no" "pvv.org" ]; networking.nameservers = [ "129.241.0.200" "129.241.0.201" ]; diff --git a/hosts/dagali/services/cyrus-sasl.nix b/hosts/dagali/services/cyrus-sasl.nix new file mode 100644 index 0000000..c9c8a28 --- /dev/null +++ b/hosts/dagali/services/cyrus-sasl.nix @@ -0,0 +1,21 @@ +{ config, ... }: +let + cfg = config.services.saslauthd; +in +{ + # TODO: This is seemingly required for openldap to authenticate + # against kerberos, but I have no idea how to configure it as + # such. Does it need a keytab? There's a binary "testsaslauthd" + # that follows with `pkgs.cyrus_sasl` that might be useful. + services.saslauthd = { + enable = true; + mechanism = "kerberos5"; + config = '' + mech_list: gs2-krb5 gssapi + keytab: /etc/krb5.keytab + ''; + }; + + # TODO: maybe the upstream module should consider doing this? + environment.systemPackages = [ cfg.package ]; +} diff --git a/hosts/dagali/services/heimdal.nix b/hosts/dagali/services/heimdal.nix new file mode 100644 index 0000000..0b07e2e --- /dev/null +++ b/hosts/dagali/services/heimdal.nix @@ -0,0 +1,80 @@ +{ config, pkgs, lib, ... }: +let + + realm = "PVV.NTNU.NO"; + + cfg = config.security.krb5; +in +{ + security.krb5 = { + enable = true; + + # NOTE: This has a small edit that moves an include header to $dev/include. + # It is required in order to build smbk5pwd, because of some nested includes. + # We should open an issue upstream (heimdal, not nixpkgs), but this patch + # will do for now. + # package = pkgs.callPackage ./package.nix { + # inherit (pkgs.apple_sdk.frameworks) + # CoreFoundation Security SystemConfiguration; + # }; + package = pkgs.heimdal.overrideAttrs (prev: { + postInstall = prev.postInstall + '' + cp include/heim_threads.h $dev/include + ''; + }); + + settings = { + # logging.kdc = "CONSOLE"; + realms.${realm} = { + admin_server = "dagali.pvv.ntnu.no"; + kdc = [ "localhost" ]; + }; + + kadmin.default_keys = lib.concatStringsSep " " [ + "aes256-cts-hmac-sha1-96:pw-salt" + "aes128-cts-hmac-sha1-96:pw-salt" + ]; + + libdefaults.default_etypes = lib.concatStringsSep " " [ + "aes256-cts-hmac-sha1-96" + "aes128-cts-hmac-sha1-96" + ]; + + libdefaults = { + default_realm = realm; + }; + + domain_realm = { + "pvv.ntnu.no" = realm; + ".pvv.ntnu.no" = realm; + }; + + logging = { + kdc = "SYSLOG:DEBUG:AUTH"; + admin_server = "SYSLOG:DEBUG:AUTH"; + default = "SYSLOG:DEBUG:AUTH"; + }; + }; + }; + + services.kerberos_server = { + enable = true; + settings = { + realms.${realm} = { + dbname = "/var/heimdal/heimdal"; + mkey = "/var/heimdal/mkey"; + }; + # kadmin.default_keys = lib.concatStringsSep " " [ + # "aes256-cts-hmac-sha1-96:pw-salt" + # "aes128-cts-hmac-sha1-96:pw-salt" + # ]; + + # libdefaults.default_etypes = lib.concatStringsSep " " [ + # "aes256-cts-hmac-sha1-96" + # "aes128-cts-hmac-sha1-96" + # ]; + + # password_quality.min_length = 8; + }; + }; +} diff --git a/hosts/dagali/services/openldap.nix b/hosts/dagali/services/openldap.nix new file mode 100644 index 0000000..5d8fca1 --- /dev/null +++ b/hosts/dagali/services/openldap.nix @@ -0,0 +1,121 @@ +{ config, pkgs, lib, ... }: +{ + services.openldap = let + dn = "dc=kerberos,dc=pvv,dc=ntnu,dc=no"; + cfg = config.services.openldap; + + heimdal = config.security.krb5.package; + in { + enable = true; + + # NOTE: this is a custom build of openldap with support for + # perl and kerberos. + package = pkgs.openldap.overrideAttrs (prev: { + # https://github.com/openldap/openldap/blob/master/configure + configureFlags = prev.configureFlags ++ [ + # Connect to slapd via UNIX socket + "--enable-local" + # Cyrus SASL + "--enable-spasswd" + # Reverse hostname lookups + "--enable-rlookups" + # perl + "--enable-perl" + ]; + + buildInputs = prev.buildInputs ++ [ + pkgs.perl + # NOTE: do not upstream this, it might not work with + # MIT in the same way + heimdal + ]; + + extraContribModules = prev.extraContribModules ++ [ + # https://git.openldap.org/openldap/openldap/-/tree/master/contrib/slapd-modules + "smbk5pwd" + ]; + }); + + settings = { + attrs = { + olcLogLevel = [ "stats" "config" "args" ]; + + # olcAuthzRegexp = '' + # gidNumber=.*\\\+uidNumber=0,cn=peercred,cn=external,cn=auth + # "uid=heimdal,${dn2}" + # ''; + + # olcSaslSecProps = "minssf=0"; + }; + + children = { + "cn=schema".includes = let + # NOTE: needed for smbk5pwd.so module + schemaToLdif = name: path: pkgs.runCommandNoCC name { + buildInputs = with pkgs; [ schema2ldif ]; + } '' + schema2ldif "${path}" > $out + ''; + + hdb-ldif = schemaToLdif "hdb.ldif" "${heimdal.src}/lib/hdb/hdb.schema"; + samba-ldif = schemaToLdif "samba.ldif" "${heimdal.src}/tests/ldap/samba.schema"; + in [ + "${cfg.package}/etc/schema/core.ldif" + "${cfg.package}/etc/schema/cosine.ldif" + "${cfg.package}/etc/schema/nis.ldif" + "${cfg.package}/etc/schema/inetorgperson.ldif" + "${hdb-ldif}" + "${samba-ldif}" + ]; + + # NOTE: installation of smbk5pwd.so module + # https://git.openldap.org/openldap/openldap/-/tree/master/contrib/slapd-modules/smbk5pwd + "cn=module{0}".attrs = { + objectClass = [ "olcModuleList" ]; + olcModuleLoad = [ "${cfg.package}/lib/modules/smbk5pwd.so" ]; + }; + + # NOTE: activation of smbk5pwd.so module for {1}mdb + "olcOverlay={0}smbk5pwd,olcDatabase={1}mdb".attrs = { + objectClass = [ "olcOverlayConfig" "olcSmbK5PwdConfig" ]; + olcOverlay = "{0}smbk5pwd"; + olcSmbK5PwdEnable = [ "krb5" "samba" ]; + olcSmbK5PwdMustChange = toString (60 * 60 * 24 * 30); + }; + + "olcDatabase={1}mdb".attrs = { + objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ]; + + olcDatabase = "{1}mdb"; + + olcSuffix = dn; + + # TODO: PW is supposed to be a secret, but it's probably fine for testing + olcRootDN = "cn=admin,${dn}"; + + # TODO: replace with proper secret + olcRootPW.path = pkgs.writeText "olcRootPW" "pass"; + + olcDbDirectory = "/var/lib/openldap/test-smbk5pwd-db"; + olcDbIndex = "objectClass eq"; + + olcAccess = [ + ''{0}to attrs=userPassword,shadowLastChange + by dn.exact=cn=admin,${dn} write + by self write + by anonymous auth + by * none'' + + ''{1}to dn.base="" + by * read'' + + /* allow read on anything else */ + # ''{2}to * + # by cn=admin,${dn} write by dn.exact=gidNumber=0+uidNumber=0+cn=peercred,cn=external write + # by * read'' + ]; + }; + }; + }; + }; +}