Enterprise identity¶
Overview¶
Enterprise Linux hosts usually resolve users and groups from LDAP or Active Directory (AD) instead of only local /etc/passwd. On NixOS the common stack is SSSD (System Security Services Daemon) for NSS/PAM lookups, optional realmd for domain enrollment helpers, and Kerberos (security.krb5) when the directory uses tickets. Domain accounts are not declared in users.users; SSSD registers NSS modules so getent passwd, login, and sudo see directory users after a rebuild.
This page covers patterns—not a full AD/LDAP tutorial. Domain-specific DNS, trust, and GPO behavior vary; verify against your directory and the NixOS option docs before production use.
Details¶
Stack roles¶
| Piece | NixOS hook | Role |
|---|---|---|
| SSSD | services.sssd.enable |
NSS/PAM (and optional SSH keys, subuid, KCM) via sssd.conf |
| realmd | services.realmd.enable |
DBus service for realm CLI enrollment (realm join, …) |
| Kerberos | security.krb5.enable + settings |
Ticket acquisition for AD/LDAP auth providers |
| Home dirs | security.pam.makeHomeDir |
Create $HOME on first login for users not in users.users |
| Join tools | environment.systemPackages |
Often adcli, krb5; enabling services.sssd adds the daemon, not these CLIs |
Declarative local accounts remain in Users and groups. Directory users are resolved through SSSD at lookup time and are not listed in users.users. With users.mutableUsers = true (default), imperative local accounts can coexist with declared ones; with false, /etc/passwd and /etc/group are replaced from users.users / users.groups on each activation (imperative locals disappear), but directory lookups still work via NSS. Many AD clients keep the default so ad-hoc local accounts survive rebuilds.
services.sssd¶
The module (nixpkgs/nixos/modules/services/misc/sssd.nix) enables the sssd systemd unit, wires NSS databases (passwd, group, shadow, services, optionally subuid/subgid), and renders /var/lib/sssd/sssd.conf at start.
Configuration shape (pick one). services.sssd.settings is an INI attrset (via formats.ini); services.sssd.config is raw INI lines. They are mutually exclusive—the module asserts exactly one is non-empty. Prefer settings in NixOS config; use config only when you already have a line-oriented sssd.conf to port.
Module options beyond sssd.conf:
| Option | Purpose |
|---|---|
sshAuthorizedKeysIntegration |
sshd uses sss_ssh_authorizedkeys; requires ssh in SSSD services |
kcm |
SSSD Kerberos Cache Manager; sets default_ccache_name = KCM: |
subIDsIntegration |
NSS subuid/subgid from SSS (containers/rootless) |
environmentFile |
systemd EnvironmentFile for secrets referenced as $VAR in config (not in the store) |
SSSD depends on nscd and network-online; it runs before user sessions. The module writes /var/lib/sssd/sssd.conf and exposes it at /etc/sssd/sssd.conf so tools like sssctl can read the live config.
Active Directory (community pattern). The NixOS Wiki AD client note describes a typical domain section with id_provider = ad, Kerberos enabled, and DNS pointing at domain controllers—confirm ad_domain, krb5_realm, and time sync (services.timesyncd or chrony) on your network. Treat wiki steps as a checklist, not guaranteed defaults.
LDAP. Use an LDAP domain section (id_provider = ldap, bind DN/password or TLS client cert). Bind passwords belong in environmentFile placeholders (see Secrets strategies), not evaluated Nix strings.
services.realmd¶
services.realmd.enable installs realmd, enables DBus, and starts the realmd service—enrollment orchestration for AD/realm membership. It does not replace SSSD configuration; you still define SSSD domains after join.
Community reports note realm join can be flaky on NixOS; many admins configure Kerberos/realmd, then run adcli join (or join from another host) and rely on SSSD for ongoing lookups. Test join paths in your lab; fallback procedures are site-specific.
Kerberos and PAM¶
For AD and many LDAP deployments, enable client Kerberos:
security.krb5.enable = true;
security.krb5.settings = {
libdefaults = {
default_realm = "EXAMPLE.COM";
};
# realms, domain_realm, KDC hostnames, … per your KDC layout
};
When services.sssd.kcm = true, ticket caching goes through SSSD’s KCM responder (module sets default_ccache_name = KCM:).
Domain users need home directories created on first login:
Some community AD guides suggest shorter nscd passwd/group cache TTLs while debugging stale IDs. SSSD already requires nscd; tune via services.nscd.settings only when you understand cache vs directory latency tradeoffs.
Secrets and networking¶
- Never put bind passwords or
ldap_default_authtokin the Nix store. Useservices.sssd.environmentFilewith placeholders insettings/config, populated from a root-only path or secrets tooling. See Secrets strategies. - DNS and reachability: clients must resolve SRV records and reach LDAP/Kerberos ports; align Networking (firewall, DNS servers, search domain) with directory docs. Time skew breaks Kerberos.
Troubleshooting sketch¶
| Symptom | Checks |
|---|---|
getent passwd misses domain user |
systemctl status sssd; sssctl domain-status; NSS order includes sss |
| Auth fails, local works | Kerberos ticket (klist), clock sync, PAM stack, SSSD logs |
| SSH key from AD | ssh in SSSD services + sshAuthorizedKeysIntegration |
| Stale groups | nscd cache TTL; sss_cache -E during tests |
More general NixOS debug flow: Troubleshooting.
Boundaries (what this page is not)¶
- Secrets strategies—agenix, sops-nix, and deploy-time credential delivery.
- Generic networking—interfaces, firewall, and DNS outside identity integration.
- Home Manager user dotfiles and per-user packages.
Examples¶
Examples below match the option shapes in nixpkgs modules (sssd.nix, realmd.nix, security/krb5, pam.nix). End-to-end login against a real directory cannot be verified offline—you need working DNS, time sync, domain join, and reachable KDC/LDAP in a lab or production forest.
Minimal AD-oriented SSSD (settings)—illustrative names only; replace realm, domain, and DC discovery with your AD layout:
{ config, pkgs, ... }: {
services.sssd.enable = true;
services.sssd.settings = {
sssd = {
services = "nss, pam";
domains = "example.com";
};
nss = { };
pam = { };
"domain/example.com" = {
id_provider = "ad";
ad_domain = "example.com";
krb5_realm = "EXAMPLE.COM";
# realmd/adcli join and DNS must match your forest
};
};
security.krb5.enable = true;
security.pam.makeHomeDir = true;
environment.systemPackages = [ pkgs.adcli pkgs.krb5 ];
}
LDAP bind secret via environmentFile (placeholder in settings, secret in the env file—not in the Nix store):
services.sssd.enable = true;
services.sssd.environmentFile = "/var/lib/secrets/sssd.env";
services.sssd.settings = {
"domain/corp" = {
id_provider = "ldap";
ldap_uri = "ldaps://ldap.corp.example";
ldap_default_bind_dn = "cn=nixos-bind,ou=svc,dc=corp,dc=example";
ldap_default_authtok = "$SSSD_LDAP_DEFAULT_AUTHTOK";
};
};
# /var/lib/secrets/sssd.env (root 0600, not in Git):
# SSSD_LDAP_DEFAULT_AUTHTOK=…
Raw config alternative—same INI as above, but only if you are not using settings:
# Do not set services.sssd.settings when using config.
services.sssd.config = ''
[domain/example.com]
id_provider = ad
ad_domain = example.com
'';
realmd + optional SSH keys from directory:
services.realmd.enable = true;
services.sssd.enable = true;
services.sssd.sshAuthorizedKeysIntegration = true;
# In settings: sssd.services must include "ssh"
References¶
- NixOS options —
services.sssd - NixOS options —
services.realmd - NixOS options —
security.krb5 - NixOS options —
security.pam.makeHomeDir - NixOS Wiki — Active Directory Client (community patterns; verify against modules)
- Upstream: SSSD documentation