Table of Contents
Defined in /modules/blocks/lldap.nix.
This block sets up an LLDAP service for user and group management across services.
shb.lldap = {
  enable = true;
  subdomain = "ldap";
  domain = "example.com";
  dcdomain = "dc=example,dc=com";
  ldapPort = 3890;
  webUIListenPort = 17170;
  jwtSecret.result = config.shb.sops.secret."lldap/jwt_secret".result;
  ldapUserPassword.result = config.shb.sops.secret."lldap/user_password".result;
};
shb.sops.secret."lldap/jwt_secret".request = config.shb.lldap.jwtSecret.request;
shb.sops.secret."lldap/user_password".request = config.shb.lldap.ldapUserPassword.request;
This assumes secrets are setup with SOPS as mentioned in the secrets setup section of the manual.
Using SSL is an important security practice, like always. Using the SSL block, the configuration to add to the one above is:
shb.certs.certs.letsencrypt.${domain}.extraDomains = [
  "${config.shb.lldap.subdomain}.${config.shb.lldap.domain}"
];
shb.lldap.ssl = config.shb.certs.certs.letsencrypt.${config.shb.lldap.domain};
For added security, you can restrict access to the LLDAP UI by adding the following line:
shb.lldap.restrictAccessIPRange = "192.168.50.0/24";
The following snippet will create group named “family” if it does not exist yet. Also, all other groups will be deleted and only the “family” group will remain.
Note that the lldap_admin, lldap_password_manager and lldap_strict_readonly groups, which are internal to LLDAP, will always exist.
If you want existing groups not declared in the shb.lldap.ensureGroups to be deleted,
set shb.lldap.enforceGroups to false.
{
  shb.lldap.ensureGroups = {
   family = {};
  };
}
Changing the configuration to the following will add a new group “friends”:
{
  shb.lldap.ensureGroups = {
    family = {};
    friends = {};
  };
}
Switching back the configuration to the previous one will delete the group “friends”:
{
  shb.lldap.ensureGroups = {
    family = {};
  };
}
Custom fields can be added to groups as long as they are added to the ensureGroupFields field:
shb.lldap = {
  ensureGroupFields = {
    mygroupattribute = {
      attributeType = "STRING";
    };
  };
  ensureGroups = {
    family = {
      mygroupattribute = "Managed by NixOS";
    };
  };
};
The following snippet creates a user and makes it a member of the “family” group.
Note the following behavior:
New users will be created following the shb.lldap.ensureUsers option.
Existing users will be updated, their password included, if they are mentioned in the shb.lldap.ensureUsers option.
Existing users not declared in the shb.lldap.ensureUsers will be left as-is.
User memberships to groups not declared in their respective shb.lldap.ensureUsers.<name>.groups.
If you want existing users not declared in the shb.lldap.ensureUsers to be deleted,
set shb.lldap.enforceUsers to true.
If you want memberships to groups not declared in the respective
shb.lldap.ensureUsers.<name>.groups option to be deleted,
set shb.lldap.enforceUserMemberships true.
{
  shb.lldap.ensureUsers = {
    dad = {
      email = "dad@example.com";
      displayName = "Dad";
      firstName = "First Name";
      lastName = "Last Name";
      groups = [ "family" ];
      password.result = config.shb.sops.secret."dad".result;
    };
  };
  shb.sops.secret."dad".request =
    shb.lldap.ensureUsers.dad.password.request;
}
The password field assumes usage of the sops block to provide secrets although any blocks providing the secrets contract works too.
The user is still editable through the UI. That being said, any change will be overwritten next time the configuration is applied.
To increase logging verbosity and see the trace of the GraphQL queries, add:
shb.lldap.debug = true;
Note that verbosity is truly verbose here so you will want to revert this at some point.
To see the logs, then run journalctl -u lldap.service.
Setting the debug option to true will also
add an shb.mitmdump instance in front of the LLDAP web UI port
which prints all requests and responses headers and body
to the systemd service mitmdump-lldap.service. Note the you won’t
see the query done using something like ldapsearch since those
go through the LDAP port.
Specific integration tests are defined in /test/blocks/lldap.nix.
shb.lldap.enable
  
 
Whether to enable the LDAP service.
Type: boolean
Default:
false
Example:
true
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.backup
  
 
Backup configuration.
Type: submodule
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.backup.request
  
 
Request part of the backup contract.
Options set by the requester module enforcing how to backup files.
Type: submodule
Default:
""
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.backup.request.excludePatterns
  
 
File patterns to exclude.
Type: list of string
Default:
[ ]
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.backup.request.hooks
  
 
Hooks to run around the backup.
Type: submodule
Default:
{ }
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.backup.request.hooks.afterBackup
  
 
Hooks to run after backup.
Type: list of string
Default:
[ ]
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.backup.request.hooks.beforeBackup
  
 
Hooks to run before backup.
Type: list of string
Default:
[ ]
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.backup.request.sourceDirectories
  
 
Directories to backup.
Type: non-empty (list of string)
Default:
[
  "/var/lib/private/lldap"
]
Example:
"/var/lib/vaultwarden"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.backup.request.user
  
 
Unix user doing the backups.
Type: string
Default:
"root"
Example:
"vaultwarden"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.backup.result
  
 
Result part of the backup contract.
Options set by the provider module that indicates the name of the backup and restor scripts.
Type: submodule
Default:
""
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.backup.result.backupService
  
 
Name of service backing up the database.
This script can be ran manually to backup the database:
$ systemctl start backup.service
Type: string
Default:
"backup.service"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.backup.result.restoreScript
  
 
Name of script that can restore the database. One can then list snapshots with:
$ restore snapshots
And restore the database with:
$ restore restore latest
Type: string
Default:
"restore"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.dcdomain
  
 
dc domain to serve.
Type: string
Example:
"dc=mydomain,dc=com"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.debug
  
 
Enable debug logging.
Type: boolean
Default:
false
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.domain
  
 
Domain under which the LDAP service will be served.
Type: string
Example:
"mydomain.com"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.enforceGroups
  
 
Remove groups not set declaratively.
Type: boolean
Default:
true
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.enforceUserMemberships
  
 
Remove users from groups not set declaratively.
Type: boolean
Default:
false
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.enforceUsers
  
 
Delete users not set declaratively.
Type: boolean
Default:
false
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureGroupFields
  
 
Extra fields for groups
Type: attribute set of (submodule)
Default:
{ }
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureGroupFields.<name>.attributeType
  
 
Attribute type.
Type: one of “STRING”, “INTEGER”, “JPEG”, “DATE_TIME”
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureGroupFields.<name>.isEditable
  
 
Is field editable.
Type: boolean
Default:
true
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureGroupFields.<name>.isList
  
 
Is field a list.
Type: boolean
Default:
false
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureGroupFields.<name>.isVisible
  
 
Is field visible in UI.
Type: boolean
Default:
true
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureGroupFields.<name>.name
  
 
Name of the field.
Type: string
Default:
"‹name›"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureGroups
  
 
Create the groups defined here on service startup.
Non-default options must be added to the ensureGroupFields option.
Type: attribute set of (open submodule of (JSON value))
Default:
{ }
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureGroups.<name>.name
  
 
Name of the group.
Type: string
Default:
"‹name›"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUserFields
  
 
Extra fields for users
Type: attribute set of (submodule)
Default:
{ }
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUserFields.<name>.attributeType
  
 
Attribute type.
Type: one of “STRING”, “INTEGER”, “JPEG”, “DATE_TIME”
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUserFields.<name>.isEditable
  
 
Is field editable.
Type: boolean
Default:
true
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUserFields.<name>.isList
  
 
Is field a list.
Type: boolean
Default:
false
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUserFields.<name>.isVisible
  
 
Is field visible in UI.
Type: boolean
Default:
true
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUserFields.<name>.name
  
 
Name of the field.
Type: string
Default:
"‹name›"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers
  
 
Create the users defined here on service startup.
If enforceUsers option is true, the groups
users belong to must be present in the ensureGroups option.
Non-default options must be added to the ensureGroupFields option.
Type: attribute set of (open submodule of (JSON value))
Default:
{ }
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.avatar_file
  
 
Avatar file. Must be a valid path to jpeg file (ignored if avatar_url specified)
Type: null or string
Default:
null
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.avatar_url
  
 
Avatar url. must be a valid URL to jpeg file (ignored if gravatar_avatar specified)
Type: null or string
Default:
null
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.displayName
  
 
Display name.
Type: null or string
Default:
null
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.email
  
 
Email.
Type: string
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.firstName
  
 
First name.
Type: null or string
Default:
null
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.gravatar_avatar
  
 
Get avatar from Gravatar using the email.
Type: null or string
Default:
null
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.groups
  
 
Groups the user would be a member of (all the groups must be specified in group config files).
Type: list of string
Default:
[ ]
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.id
  
 
Username.
Type: string
Default:
"‹name›"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.lastName
  
 
Last name.
Type: null or string
Default:
null
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.password
  
 
Password.
Type: submodule
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.password.request
  
 
Request part of the secret contract.
Options set by the requester module enforcing some properties the secret should have.
Type: submodule
Default:
""
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.password.request.group
  
 
Linux group owning the secret file.
Type: string
Default:
"lldap"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.password.request.mode
  
 
Mode of the secret file.
Type: string
Default:
"0440"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.password.request.owner
  
 
Linux user owning the secret file.
Type: string
Default:
"lldap"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.password.request.restartUnits
  
 
Systemd units to restart after the secret is updated.
Type: list of string
Default:
[
  "lldap.service"
]
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.password.result
  
 
Result part of the secret contract.
Options set by the provider module that indicates where the secret can be found.
Type: submodule
Default:
{
  path = "/run/secrets/secret";
}
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.password.result.path
  
 
Path to the file containing the secret generated out of band.
This path will exist after deploying to a target host, it is not available through the nix store.
Type: absolute path
Default:
"/run/secrets/secret"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ensureUsers.<name>.weser_avatar
  
 
Convert avatar retrieved by gravatar or the URL.
Type: null or string
Default:
null
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.jwtSecret
  
 
JWT secret.
Type: submodule
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.jwtSecret.request
  
 
Request part of the secret contract.
Options set by the requester module enforcing some properties the secret should have.
Type: submodule
Default:
""
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.jwtSecret.request.group
  
 
Linux group owning the secret file.
Type: string
Default:
"lldap"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.jwtSecret.request.mode
  
 
Mode of the secret file.
Type: string
Default:
"0440"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.jwtSecret.request.owner
  
 
Linux user owning the secret file.
Type: string
Default:
"lldap"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.jwtSecret.request.restartUnits
  
 
Systemd units to restart after the secret is updated.
Type: list of string
Default:
[
  "lldap.service"
]
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.jwtSecret.result
  
 
Result part of the secret contract.
Options set by the provider module that indicates where the secret can be found.
Type: submodule
Default:
{
  path = "/run/secrets/secret";
}
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.jwtSecret.result.path
  
 
Path to the file containing the secret generated out of band.
This path will exist after deploying to a target host, it is not available through the nix store.
Type: absolute path
Default:
"/run/secrets/secret"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ldapPort
  
 
Port on which the server listens for the LDAP protocol.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
3890
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ldapUserPassword
  
 
LDAP admin user secret.
Type: submodule
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ldapUserPassword.request
  
 
Request part of the secret contract.
Options set by the requester module enforcing some properties the secret should have.
Type: submodule
Default:
""
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ldapUserPassword.request.group
  
 
Linux group owning the secret file.
Type: string
Default:
"lldap"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ldapUserPassword.request.mode
  
 
Mode of the secret file.
Type: string
Default:
"0440"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ldapUserPassword.request.owner
  
 
Linux user owning the secret file.
Type: string
Default:
"lldap"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ldapUserPassword.request.restartUnits
  
 
Systemd units to restart after the secret is updated.
Type: list of string
Default:
[
  "lldap.service"
]
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ldapUserPassword.result
  
 
Result part of the secret contract.
Options set by the provider module that indicates where the secret can be found.
Type: submodule
Default:
{
  path = "/run/secrets/secret";
}
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ldapUserPassword.result.path
  
 
Path to the file containing the secret generated out of band.
This path will exist after deploying to a target host, it is not available through the nix store.
Type: absolute path
Default:
"/run/secrets/secret"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.mount
  
 
Mount configuration. This is an output option.
Use it to initialize a block implementing the “mount” contract. For example, with a zfs dataset:
shb.zfs.datasets."ldap" = {
  poolName = "root";
} // config.shb.lldap.mount;
Type: open submodule of anything (read only)
Default:
{
  path = "/var/lib/lldap";
}
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.mount.path
  
 
Path to be mounted.
Type: string
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.restrictAccessIPRange
  
 
Set a local network range to restrict access to the UI to only those IPs.
Type: null or string
Default:
null
Example:
"192.168.1.1/24"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ssl
  
 
Path to SSL files
Type: null or (open submodule of anything)
Default:
null
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ssl.paths
  
 
Paths where the files for the certificate will be located.
This option is the contract output of the shb.certs.certs SSL block.
Type: open submodule of anything
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ssl.paths.cert
  
 
Path to the cert file.
Type: absolute path
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ssl.paths.key
  
 
Path to the key file.
Type: absolute path
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.ssl.systemdService
  
 
Systemd oneshot service used to generate the certificate. Ends with the .service suffix.
Use this if downstream services must wait for the certificates to be generated before starting.
Type: string
Example:
"cert-generator.service"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.subdomain
  
 
Subdomain under which the LDAP service will be served.
Type: string
Example:
"grafana"
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 | 
shb.lldap.webUIListenPort
  
 
Port on which the web UI is exposed.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
17170
Declared by:
<selfhostblocks/modules/blocks/lldap.nix>
 |