feat(sssd): authenticate NixOS hosts against Authentik LDAP via agenix #55
@@ -0,0 +1,130 @@
|
||||
# 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 = <the bind password>
|
||||
#
|
||||
# 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;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user