# Authentik LDAP authentication for NixOS hosts. # # Wires SSSD (System Security Services Daemon) to the Authentik LDAP outpost so # every Linux host authenticates users against the same directory that backs the # SSO stack. Enabled by default on every NixOS host via baseModules; the EDaaS # WSL box opts out (services.authentikLdap.enable = false) because it is a # work-managed Windows-hosted environment. # # The Authentik LDAP provider exposes NON-standard object classes/attributes # (goauthentik.io/ldap/user, goauthentik.io/ldap/group) alongside the POSIX # attributes (uid, uidNumber, gidNumber, homeDirectory), so the schema mappings # below are explicit rather than relying on an RFC2307 default. # # The bind password is NOT inlined: services.sssd.config renders to the world- # readable Nix store, so the credential is delivered out-of-band by agenix as an # sssd.conf drop-in under /etc/sssd/conf.d/ (SSSD merges conf.d/*.conf after the # main file). See secrets/README.md. { config, lib, ... }: let cfg = config.services.authentikLdap; # Directory coordinates for the Authentik LDAP provider. ldapUri = "ldaps://ldap.lyrapup.pet:636"; searchBase = "dc=ldap,dc=goauthentik,dc=io"; bindDn = "cn=sssd-bind,ou=users,dc=ldap,dc=goauthentik,dc=io"; in { options.services.authentikLdap.enable = lib.mkEnableOption "SSSD authentication against the Authentik LDAP outpost" // { default = true; }; config = lib.mkIf cfg.enable { services.sssd = { enable = true; # Non-secret sssd.conf. The bind password is injected separately via the # agenix conf.d drop-in (ldap_default_authtok lives there, not here) to # keep it out of the Nix store. config = '' [sssd] config_file_version = 2 services = nss, pam domains = default [nss] # Do not walk the whole directory for `getent passwd` etc. filter_users = root filter_groups = root [pam] [domain/default] # --- Providers -------------------------------------------------------- id_provider = ldap auth_provider = ldap chpass_provider = none access_provider = permit # --- Connection ------------------------------------------------------- ldap_uri = ${ldapUri} ldap_search_base = ${searchBase} ldap_default_bind_dn = ${bindDn} ldap_default_authtok_type = password # ldap_default_authtok is supplied by the agenix drop-in in conf.d. # --- TLS (LDAPS on 636; no StartTLS) --------------------------------- ldap_id_use_start_tls = false ldap_tls_reqcert = demand # --- Schema: Authentik LDAP provider --------------------------------- # Authentik returns DN-valued group membership (member/memberOf), so # rfc2307bis (not rfc2307) is the correct base schema. ldap_schema = rfc2307bis # Users: goauthentik.io/ldap/user, keyed by uid; POSIX attrs are # standard names (uidNumber/gidNumber/homeDirectory). ldap_user_object_class = goauthentik.io/ldap/user ldap_user_name = uid ldap_user_uid_number = uidNumber ldap_user_gid_number = gidNumber ldap_user_home_directory = homeDirectory ldap_user_gecos = displayName ldap_user_shell = loginShell # Groups: goauthentik.io/ldap/group, keyed by cn. ldap_group_object_class = goauthentik.io/ldap/group ldap_group_name = cn ldap_group_gid_number = gidNumber ldap_group_member = member # --- Behaviour -------------------------------------------------------- cache_credentials = true enumerate = false ''; }; # agenix delivers the bind password as an sssd.conf drop-in. The decrypted # plaintext IS a valid conf.d snippet: # # [domain/default] # ldap_default_authtok = # # SSSD requires conf.d files to be root-owned and 0600 or it ignores them. age.secrets.ldap-bind = { file = ../secrets/ldap-bind.age; path = "/etc/sssd/conf.d/01-ldap-authtok.conf"; owner = "root"; group = "root"; mode = "0600"; }; # Restart SSSD when the credential drop-in changes. agenix writes secrets in # a system activation script that runs before systemd (re)starts services on # a `switch`, so the file is present by the time sssd starts; the trigger # picks up rotations of the bind password. systemd.services.sssd.restartTriggers = [ config.age.secrets.ldap-bind.path ]; # Create home directories on first login for LDAP users (they have no # locally-provisioned home). NixOS wires nss + the SSSD PAM stack when # services.sssd.enable is true; mkHomeDir adds pam_mkhomedir to it. security.pam.services.login.makeHomeDir = true; security.pam.services.sshd.makeHomeDir = true; }; }