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