selfhostblocks/modules/blocks/lldap/docs/default.md
2026-02-27 13:18:03 +01:00

6.1 KiB

LLDAP Block

Defined in /modules/blocks/lldap.nix.

This block sets up an LLDAP service for user and group management across services.

Features

Usage

Initial Configuration

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.

SSL

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};

Restrict Access By IP

For added security, you can restrict access to the LLDAP UI by adding the following line:

shb.lldap.restrictAccessIPRange = "192.168.50.0/24";

Application Dashboard

Integration with the dashboard contract is provided by the dashboard option.

For example using the Homepage service:

{
  shb.homepage.servicesGroups.Admin.services.LLDAP = {
    sortOrder = 2;
    dashboard.request = config.shb.lldap.dashboard.request;
  };
}

Manage Groups

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 true.

{
  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";
    };
  };
};

Manage Users

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 =
    config.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.

Troubleshooting

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.

Tests

Specific integration tests are defined in /test/blocks/lldap.nix.

Options Reference

id-prefix: blocks-lldap-options-
list-id: selfhostblocks-block-lldap-options
source: @OPTIONS_JSON@