server-configs/machines/gerd/services/lldap.nix
2024-09-01 20:07:20 +02:00

164 lines
5.2 KiB
Nix

{ config, lib, pkgs, ... }:
let
svc_domain = "ldap.${config.mine.shared.settings.domain}";
resetPasswordStartPatch = pkgs.writeText "lldap-reset-password-start.patch" ''
diff --git a/server/src/main.rs b/server/src/main.rs
index 71e4928..63be13c 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -158,7 +158,7 @@ async fn set_up_server(config: Configuration) -> Result<ServerBuilder> {
))?;
}
if config.force_update_private_key || config.force_ldap_user_pass_reset {
- bail!("Restart the server without --force-update-private-key or --force-ldap-user-pass-reset to continue.");
+ // bail!("Restart the server without --force-update-private-key or --force-ldap-user-pass-reset to continue.");
}
let server_builder = infra::ldap_server::build_ldap_server(
&config,
'';
pkgLLDAPCli = pkgs.callPackage ./../../../shared/pkgs/lldap-cli.nix {};
in {
environment.systemPackages = [
pkgLLDAPCli
];
services.lldap = {
enable = true;
package = pkgs.lldap.overrideAttrs (old: {
patches = old.patches ++ [ resetPasswordStartPatch ];
});
settings = {
verbose = true;
ldap_user_email = "fricloudlldap.grief462@simplelogin.com";
ldap_base_dn = config.mine.shared.settings.ldap.dc;
};
environment = {
# always set admin password on startup
LLDAP_LDAP_USER_PASS_FILE = config.age.secrets.lldap-admin-user-pass.path;
LLDAP_FORCE_LDAP_USER_PASS_RESET = "true";
};
};
services.nginx.virtualHosts."${svc_domain}" = {
forceSSL = true;
enableACME = true;
locations."/".proxyPass = "http://localhost:${builtins.toString config.services.lldap.settings.http_port}";
};
# persistent files
environment.persistence.root.directories = [
{ directory = "/var/lib/private/lldap"; mode = "0700"; }
];
# lldap user + setup secrets owner (need to add user for secrets to work)
users.users.lldap = { group = "lldap"; isSystemUser = true; };
users.groups.lldap = {};
age.secrets = {
lldap-admin-user-pass.owner = "lldap";
};
# set settings other services can use
# CN = Common Name
# OU = Organizational Unit
# DC = Domain Component
#
# The users are all located in ou=people, + the base DN, so by default user bob is at cn=bob,ou=people,dc=example,dc=com.
# Similarly, the groups are located in ou=groups, so the group family will be at cn=family,ou=groups,dc=example,dc=com.
# Testing group membership through memberOf is supported, so you can have a filter like: (memberOf=cn=admins,ou=groups,dc=example,dc=com).
mine.shared.settings.ldap = rec {
host = "localhost";
port = 3890;
url = "ldap://${host}:${builtins.toString port}";
dc = "dc=${config.mine.shared.settings.domain_sld},dc=${config.mine.shared.settings.domain_tld}";
bind_dn = "uid=${users.bind},ou=${ou.users},${dc}";
search_base = "ou=${ou.users},${dc}";
user_filter = ph: let
attrs = [ attr.uid attr.email ];
in config.mine.shared.lib.ldap.mkFilter (lconfig: llib:
llib.mkAnd [
(llib.mkGroup lconfig.groups.member)
(llib.mkOr (lib.forEach attrs (v: llib.mkSearch v ph)))
]
);
oc = {
person = "person";
mailAccount = "mailAccount";
groupOfUniqueNames = "groupOfUniqueNames";
};
users = {
admin = "admin";
bind = "bind_user";
};
groups = {
admin = "lldap_admin";
member = "base_member";
};
ou = {
groups = "groups";
users = "people";
};
attr = {
uid = "uid";
firstname = "givenName";
lastname = "sn";
email = "mail";
avatar = "jpegPhoto";
groupname = "cn";
};
age_secret = config.age.secrets.lldap-bind-user-pass.path;
};
mine.shared.lib.ldap = rec {
mkGroup = group_name: "memberof=cn=${group_name},ou=${config.mine.shared.settings.ldap.ou.groups},${config.mine.shared.settings.ldap.dc}";
mkOC = object_class_name: "objectclass=${object_class_name}";
mkSearch = attribute: ph: "${attribute}=${ph}";
mkFilterAdvanced = expr: let
isExpr = value: if value ? type then true else false;
__mkExpr = value: if isExpr value then mkFilterAdvanced value else "(${value})";
_mkExpr = op: value: "(${op}" + (builtins.concatStringsSep "" (lib.forEach value (v: __mkExpr v))) + ")";
mkExpr = expr: assert isExpr expr; if expr.type == "and" then _mkExpr "&" expr.values else _mkExpr "|" expr.values;
in mkExpr expr;
mkAndOr = andExprs: orExprs: mkFilterAdvanced {
type = "and";
values = andExprs ++ [
{ type = "or"; values = orExprs; }
];
};
mkFilter = t: mkFilterAdvanced (t config.mine.shared.settings.ldap config.mine.shared.lib.ldap);
mkScope = t: t config.mine.shared.settings.ldap config.mine.shared.lib.ldap;
mkAnd = v: { type = "and"; values = v; };
mkOr = v: { type = "or"; values = v; };
};
mine.shared.meta.lldap = {
name = "LDAP";
description = "We host our own LDAP server, you can use it to change your displayname, name, password, etc.";
url = "https://${svc_domain}";
package = let
pkg = config.services.lldap.package;
in {
name = pkg.pname;
version = pkg.version;
meta = pkg.meta;
};
};
}