diff --git a/machines/gerd/services/authelia/authelia.nix b/machines/gerd/services/authelia/authelia.nix index 3ec8f86..084e178 100644 --- a/machines/gerd/services/authelia/authelia.nix +++ b/machines/gerd/services/authelia/authelia.nix @@ -81,6 +81,11 @@ in { }; }; + # setup lldap user for authelia that can send emails + services.lldap.provision.users = config.mine.shared.lib.ldap.mkScope (lconfig: llib: { + authelia = llib.mkProvisionUserSystem "authelia" config.age.secrets.authelia-smtp-password.path; + }); + services.nginx.virtualHosts."${svc_domain}" = { forceSSL = true; enableACME = true; diff --git a/machines/gerd/services/lldap/bootstrap/lldap-state-module.nix b/machines/gerd/services/lldap/bootstrap/lldap-state-module.nix deleted file mode 100644 index 2d71647..0000000 --- a/machines/gerd/services/lldap/bootstrap/lldap-state-module.nix +++ /dev/null @@ -1,148 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - inherit (lib) types; - - cfg = config.mine.lldap_provision; - - # helpers - _configFile = { - user_attributes = lib.mapAttrsToList (n: v: v) cfg.user_attributes; - group_attributes = lib.mapAttrsToList (n: v: v) cfg.group_attributes; - users = lib.mapAttrsToList (n: v: v // { - user_id = if v ? user_id then v.user_id else n; - }) cfg.users; - groups = lib.mapAttrsToList (n: v: v // { - display_name = if v ? display_name then v.display_name else n; - }) cfg.groups; - }; - configFile = (pkgs.formats.json {}).generate "lldap-declarative.json" _configFile; - - # opts - optsAttributes = { name, config, ... }: { - options = { - name = lib.mkOption { - type = types.str; - default = name; - description = "The name of the attribute"; - }; - - attributeType = lib.mkOption { - type = types.enum [ "STRING" "INTEGER" "JPEG_PHOTO" "DATE_TIME" ]; - description = "Type of the attribute"; - }; - - isList = lib.mkOption { - type = types.bool; - default = false; - description = "Is this attribute a list (multiple values for this attribute)"; - }; - - isEditable = lib.mkOption { - type = types.bool; - default = false; - description = "Should the user be able to edit this value?"; - }; - - isVisible = lib.mkOption { - type = types.bool; - default = false; - description = "Should the user be able to see this value?"; - }; - }; - }; - -in { - options = { - mine.lldap_provision = { - enable = lib.mkEnableOption "LLDAP declarative setup"; - - url = lib.mkOption { - type = types.str; - default = config.services.lldap.settings.http_url; - description = "URL for the LLDAP instance"; - - }; - - username = lib.mkOption { - type = types.str; - description = "Username to use when signing into lldap"; - }; - - passwordFile = lib.mkOption { - type = types.path; - description = "Path for the password file to authenticate the user"; - }; - - group_attributes = lib.mkOption { - type = types.attrsOf (types.submodule optsAttributes); - default = {}; - }; - - user_attributes = lib.mkOption { - type = types.attrsOf (types.submodule optsAttributes); - default = {}; - }; - - users = lib.mkOption { - type = types.attrsOf types.anything; - default = {}; - example = { - user1 = { - password = "env:LLDAP_USER1_PASSWORD"; - mail = "something@something.dk"; - - foo = "value for user attribute foo"; - bar = "value for user attribute bar"; - groups = [ "group1" "group2" ]; - }; - user2 = { user_id = "superuserawesome"; }; - }; - }; - - groups = lib.mkOption { - type = types.attrsOf types.anything; - default = {}; - example = { - base_member = { - foo = "value for group attribute foo"; - bar = "value for group attribute bar"; - }; - system = { - display_name = "system_service - override display_name"; - }; - testgroup = {}; - }; - }; - }; - }; - - config = lib.mkIf cfg.enable { - systemd.services.lldapsetup = { - description = "setup lldap declaratively"; - wantedBy = [ config.systemd.services.lldap.name "multi-user.target" ]; - after = [ config.systemd.services.lldap.name ]; - - environment = { - LLDAP_URL = cfg.url; - LLDAP_USERNAME = cfg.username; - LLDAP_PASSWORD = "file:${cfg.passwordFile}"; - }; - - path = with pkgs; [ - lldap - ]; - - script = let - pythonEnv = pkgs.python3.withPackages(ps: with ps; [ gql aiohttp requests ]); - pythonDir = pkgs.runCommand "lldap-bootstrap" {} '' - mkdir -p $out/bootstrap - cp -a ${./.}/. $out/bootstrap - ''; - in '' - cd ${pythonDir} - ${pythonEnv}/bin/python -m bootstrap.main ${configFile} - ''; - }; - }; -} diff --git a/machines/gerd/services/lldap/default.nix b/machines/gerd/services/lldap/default.nix index 290bb0c..62be56e 100644 --- a/machines/gerd/services/lldap/default.nix +++ b/machines/gerd/services/lldap/default.nix @@ -19,10 +19,88 @@ index 6f42473..b3746a1 100644 &config, ''; + whoamiPatch = pkgs.writeText "lldap-whoami.patch" '' +diff --git a/server/src/infra/ldap_handler.rs b/server/src/infra/ldap_handler.rs +index 7257c31..feda03c 100644 +--- a/server/src/infra/ldap_handler.rs ++++ b/server/src/infra/ldap_handler.rs +@@ -26,7 +26,7 @@ use ldap3_proto::proto::{ + LdapDerefAliases, LdapExtendedRequest, LdapExtendedResponse, LdapFilter, LdapModify, + LdapModifyRequest, LdapModifyType, LdapOp, LdapPartialAttribute, LdapPasswordModifyRequest, + LdapResult as LdapResultOp, LdapResultCode, LdapSearchRequest, LdapSearchResultEntry, +- LdapSearchScope, ++ LdapSearchScope, OID_PASSWORD_MODIFY, OID_WHOAMI, + }; + use std::collections::HashMap; + use tracing::{debug, instrument, warn}; +@@ -181,7 +181,7 @@ fn root_dse_response(base_dn: &str) -> LdapOp { + LdapPartialAttribute { + atype: "supportedExtension".to_string(), + // Password modification extension. +- vals: vec![b"1.3.6.1.4.1.4203.1.11.1".to_vec()], ++ vals: vec![OID_PASSWORD_MODIFY.as_bytes().to_vec()], + }, + LdapPartialAttribute { + atype: "supportedControl".to_string(), +@@ -204,6 +204,11 @@ fn root_dse_response(base_dn: &str) -> LdapOp { + atype: "isGlobalCatalogReady".to_string(), + vals: vec![b"false".to_vec()], + }, ++ LdapPartialAttribute { ++ atype: "supportedExtension".to_string(), ++ // whoami extension. ++ vals: vec![OID_WHOAMI.as_bytes().to_vec()], ++ }, + ], + }) + } +@@ -413,16 +418,33 @@ impl LdapHandler Vec { +- match LdapPasswordModifyRequest::try_from(request) { +- Ok(password_request) => self ++ if let Ok(password_request) = LdapPasswordModifyRequest::try_from(request) { ++ return self + .do_password_modification(&password_request) + .await +- .unwrap_or_else(|e: LdapError| vec![make_extended_response(e.code, e.message)]), +- Err(_) => vec![make_extended_response( +- LdapResultCode::UnwillingToPerform, +- format!("Unsupported extended operation: {}", &request.name), +- )], ++ .unwrap_or_else(|e: LdapError| vec![make_extended_response(e.code, e.message)]); + } ++ ++ if request.name == OID_WHOAMI { ++ let dn = self ++ .user_info ++ .as_ref() ++ .map(|user_info| { ++ format!( ++ "dn:uid={},ou=people,{}", ++ user_info.user.clone().into_string(), ++ self.ldap_info.base_dn_str ++ ) ++ }) ++ .unwrap_or_default(); ++ ++ return vec![make_extended_response(LdapResultCode::Success, dn)]; ++ } ++ ++ return vec![make_extended_response( ++ LdapResultCode::UnwillingToPerform, ++ format!("Unsupported extended operation: {}", &request.name), ++ )]; + } + + async fn handle_modify_change( +''; + pkgLLDAPCli = pkgs.callPackage ./../../../../shared/pkgs/lldap-cli.nix {}; in { imports = [ - # ./test.nix + ./provision.nix ]; environment.systemPackages = [ @@ -33,7 +111,7 @@ in { enable = true; package = pkgs.lldap.overrideAttrs (old: { - patches = old.patches ++ [ resetPasswordStartPatch ]; + patches = old.patches ++ [ resetPasswordStartPatch whoamiPatch ]; }); settings = { @@ -100,22 +178,29 @@ in { users = { admin = "admin"; - bind = "bind_user"; - }; + # bind = "bind_user"; + } // (lib.mapAttrs (n: v: v.user_id) config.services.lldap.provision.users); groups = { admin = "lldap_admin"; member = "base_member"; - system = "system_service"; - system_email = "system_email"; - }; + password_manager = "lldap_password_manager"; + strict_readonly = "lldap_strict_readonly"; + # system = "system_service"; + # system_email = "system_email"; + } // (lib.mapAttrs (n: v: v.display_name) config.services.lldap.provision.groups); ou = { groups = "groups"; users = "people"; }; - attr = { + attr = let + toCamelCase = w: let + parts = lib.splitString "_" w; + cap = lib.imap0 (i: v: if i == 0 then v else (lib.toUpper (lib.substring 0 1 v)) + (lib.substring 1 (lib.stringLength v) v)); + in lib.concatStrings (cap parts); + in { uid = "uid"; firstname = "givenName"; lastname = "sn"; @@ -124,9 +209,9 @@ in { groupname = "cn"; # custom - member_email = "member_email"; - mail_disk_quota = "mail_disk_quota"; - }; + # member_email = "member_email"; + # mail_disk_quota = "mail_disk_quota"; + } // (lib.mapAttrs (n: v: toCamelCase v.name) config.services.lldap.provision.user_attributes); age_secret = config.age.secrets.lldap-bind-user-pass.path; }; @@ -156,6 +241,31 @@ in { mkAnd = v: { type = "and"; values = v; }; mkOr = v: { type = "or"; values = v; }; + + # mkProvision helpers for creating users + mkProvisionEmail = name: "${name}@${config.mine.shared.settings.domain}"; + mkProvisionUserNormal = name: config.mine.shared.lib.ldap.mkScope (lconfig: llib: { + user_id = name; + membermail = mkProvisionEmail name; + mail = "env:EMAIL_${lib.toUpper name}"; + groups = [ lconfig.groups.member ]; + membermaildiskquota = 100*1024*1024; # mb + }); + + mkProvisionUserSystem = name: password_file: config.mine.shared.lib.ldap.mkScope (lconfig: llib: { + user_id = name; + membermail = mkProvisionEmail name; + password = "file:${password_file}"; + groups = [ lconfig.groups.system_mail lconfig.groups.system_service ]; + membermaildiskquota = 10*1024*1024; # mb + }); + + mkProvisionUserAdmin = name: config.mine.shared.lib.ldap.mkScope (lconfig: llib: { + user_id = name; + membermail = mkProvisionEmail name; + groups = [ lconfig.groups.admin lconfig.groups.member ]; + membermaildiskquota = 100*1024*1024; # mb + }); }; mine.shared.meta.lldap = { diff --git a/machines/gerd/services/lldap/bootstrap/attributes.py b/machines/gerd/services/lldap/module/bootstrap/attributes.py similarity index 100% rename from machines/gerd/services/lldap/bootstrap/attributes.py rename to machines/gerd/services/lldap/module/bootstrap/attributes.py diff --git a/machines/gerd/services/lldap/bootstrap/example.json b/machines/gerd/services/lldap/module/bootstrap/example.json similarity index 100% rename from machines/gerd/services/lldap/bootstrap/example.json rename to machines/gerd/services/lldap/module/bootstrap/example.json diff --git a/machines/gerd/services/lldap/bootstrap/groups.py b/machines/gerd/services/lldap/module/bootstrap/groups.py similarity index 98% rename from machines/gerd/services/lldap/bootstrap/groups.py rename to machines/gerd/services/lldap/module/bootstrap/groups.py index 9868449..63d1685 100644 --- a/machines/gerd/services/lldap/bootstrap/groups.py +++ b/machines/gerd/services/lldap/module/bootstrap/groups.py @@ -104,7 +104,7 @@ class LLDAPGroups: if isinstance(v, str): v = [v] - insertAttributes.append({"name": to_snakecase(k), "value": v}) + insertAttributes.append({"name": k, "value": v}) ds = DSLSchema(self._client.schema) query = dsl_gql( diff --git a/machines/gerd/services/lldap/bootstrap/main.py b/machines/gerd/services/lldap/module/bootstrap/main.py similarity index 99% rename from machines/gerd/services/lldap/bootstrap/main.py rename to machines/gerd/services/lldap/module/bootstrap/main.py index 4d8cb50..e697fcf 100644 --- a/machines/gerd/services/lldap/bootstrap/main.py +++ b/machines/gerd/services/lldap/module/bootstrap/main.py @@ -22,7 +22,7 @@ from .attributes import LLDAPAttributes import logging logging.basicConfig() -logging.getLogger("lldapbootstrap").setLevel(logging.DEBUG) +logging.getLogger("bootstrap").setLevel(logging.DEBUG) logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) diff --git a/machines/gerd/services/lldap/bootstrap/users.py b/machines/gerd/services/lldap/module/bootstrap/users.py similarity index 98% rename from machines/gerd/services/lldap/bootstrap/users.py rename to machines/gerd/services/lldap/module/bootstrap/users.py index 10f1f7b..bcedfd4 100644 --- a/machines/gerd/services/lldap/bootstrap/users.py +++ b/machines/gerd/services/lldap/module/bootstrap/users.py @@ -95,7 +95,7 @@ class LLDAPUsers: if isinstance(v, str): v = [v] - insertAttributes.append({"name": to_snakecase(k), "value": v}) + insertAttributes.append({"name": k, "value": v}) ds = DSLSchema(self._client.schema) query = dsl_gql( diff --git a/machines/gerd/services/lldap/bootstrap/utils.py b/machines/gerd/services/lldap/module/bootstrap/utils.py similarity index 100% rename from machines/gerd/services/lldap/bootstrap/utils.py rename to machines/gerd/services/lldap/module/bootstrap/utils.py diff --git a/machines/gerd/services/lldap/module/default.nix b/machines/gerd/services/lldap/module/default.nix new file mode 100644 index 0000000..04032c4 --- /dev/null +++ b/machines/gerd/services/lldap/module/default.nix @@ -0,0 +1,166 @@ +{ config, lib, pkgs, ... }: + +let + inherit (lib) types; + + cfg = config.services.lldap; + format = pkgs.formats.json { }; + + # helpers + _configFile = { + user_attributes = lib.mapAttrsToList (n: v: v) cfg.provision.user_attributes; + group_attributes = lib.mapAttrsToList (n: v: v) cfg.provision.group_attributes; + users = lib.mapAttrsToList (n: v: v) cfg.provision.users; + groups = lib.mapAttrsToList (n: v: v) cfg.provision.groups; + # users = lib.mapAttrsToList (n: v: v // { + # user_id = if v ? user_id then v.user_id else n; + # }) cfg.users; + # groups = lib.mapAttrsToList (n: v: v // { + # display_name = if v ? display_name then v.display_name else n; + # }) cfg.groups; + }; + configFile = format.generate "lldap-declarative.json" _configFile; + + # opts + optsAttributes = { name, config, ... }: { + options = { + name = lib.mkOption { + type = types.str; + default = name; + description = "The name of the attribute"; + }; + + attributeType = lib.mkOption { + type = types.enum [ "STRING" "INTEGER" "JPEG_PHOTO" "DATE_TIME" ]; + description = "Type of the attribute"; + }; + + isList = lib.mkOption { + type = types.bool; + default = false; + description = "Is this attribute a list (multiple values for this attribute)"; + }; + + isEditable = lib.mkOption { + type = types.bool; + default = false; + description = "Should the user be able to edit this value?"; + }; + + isVisible = lib.mkOption { + type = types.bool; + default = false; + description = "Should the user be able to see this value?"; + }; + }; + }; + + optsUser = { name, config, ... }: { + freeformType = format.type; + options = { + user_id = lib.mkOption { + type = types.str; + default = name; + description = "The name of the user"; + }; + }; + }; + + optsGroup = { name, config, ... }: { + freeformType = format.type; + options = { + display_name = lib.mkOption { + type = types.str; + default = name; + description = "The display name of the group"; + }; + }; + }; + +in { + options = { + services.lldap = { + provisionUsername = lib.mkOption { + type = types.str; + description = "Username to use when signing into lldap"; + }; + + provisionPasswordFile = lib.mkOption { + type = types.path; + description = "Path for the password file to authenticate the user"; + }; + + provision = { + group_attributes = lib.mkOption { + type = types.attrsOf (types.submodule optsAttributes); + default = {}; + }; + + user_attributes = lib.mkOption { + type = types.attrsOf (types.submodule optsAttributes); + default = {}; + }; + + users = lib.mkOption { + type = types.attrsOf (types.submodule optsUser); + default = {}; + example = { + user1 = { + password = "env:LLDAP_USER1_PASSWORD"; + mail = "something@something.dk"; + + foo = "value for user attribute foo"; + bar = "value for user attribute bar"; + groups = [ "group1" "group2" ]; + }; + user2 = { user_id = "superuserawesome"; }; + }; + }; + + groups = lib.mkOption { + type = types.attrsOf (types.submodule optsGroup); + default = {}; + example = { + base_member = { + foo = "value for group attribute foo"; + bar = "value for group attribute bar"; + }; + system = { + display_name = "system_service - override display_name"; + }; + testgroup = {}; + }; + }; + }; + }; + }; + + config = lib.mkIf (cfg.enable && cfg.provision != {}) { + systemd.services.lldapsetup = { + description = "setup lldap declaratively"; + wantedBy = [ config.systemd.services.lldap.name "multi-user.target" ]; + after = [ config.systemd.services.lldap.name ]; + + environment = { + LLDAP_URL = "${cfg.settings.http_url}:${builtins.toString cfg.settings.http_port}"; + LLDAP_USERNAME = cfg.provisionUsername; + LLDAP_PASSWORD = "file:${cfg.provisionPasswordFile}"; + }; + + path = with pkgs; [ + lldap + ]; + + script = let + pythonEnv = pkgs.python3.withPackages(ps: with ps; [ gql aiohttp requests ]); + pythonDir = pkgs.runCommand "lldap-bootstrap" {} '' + mkdir -p $out/bootstrap + cp -a ${./bootstrap}/. $out/bootstrap + ''; + in '' + cd ${pythonDir} + ${pythonEnv}/bin/python -m bootstrap.main ${configFile} + ''; + }; + }; +} diff --git a/machines/gerd/services/lldap/provision.nix b/machines/gerd/services/lldap/provision.nix new file mode 100644 index 0000000..2792d8c --- /dev/null +++ b/machines/gerd/services/lldap/provision.nix @@ -0,0 +1,68 @@ +{ config, lib, ... }: + +{ + imports = [ + ./module + ]; + + services.lldap = { + provisionUsername = "admin"; + provisionPasswordFile = config.age.secrets.lldap-admin-user-pass.path; + + provision = config.mine.shared.lib.ldap.mkScope (lconfig: llib: { + # users + users = { + # normal users + testusername = { + membermail = "env:EMAIL_EMAIL0"; + groups = [ config.services.lldap.provision.groups.system_mail.display_name ]; + }; + + user1 = llib.mkProvisionUserNormal "thief420"; + + # admin users + admin = llib.mkProvisionUserAdmin "admin"; + eyjhb = llib.mkProvisionUserAdmin "eyjhb"; + rasmus = llib.mkProvisionUserAdmin "rasmus"; + + # system users - defined in each service + # should not be done here + + # bind user + bind = { + user_id = "bind_user"; + groups = [ lconfig.groups.password_manager lconfig.groups.strict_readonly ]; + }; + }; + + # groups + groups = { + "base_member" = {}; + "system_service" = {}; + "system_mail" = {}; + }; + + # attributes + group_attributes = { + group_foo = { + attributeType = "STRING"; + isEditable = true; + isVisible = true; + }; + }; + user_attributes = { + membermail = { + attributeType = "STRING"; + isEditable = false; + isVisible = true; + }; + membermaildiskquota = { + attributeType = "INTEGER"; + }; + }; + + }); + }; + + systemd.services.lldapsetup.serviceConfig.EnvironmentFile = config.age.secrets.lldap-user-emails-env.path; +} diff --git a/machines/gerd/services/lldap/test.nix b/machines/gerd/services/lldap/test.nix deleted file mode 100644 index 5911586..0000000 --- a/machines/gerd/services/lldap/test.nix +++ /dev/null @@ -1,98 +0,0 @@ -{ config, lib, ... }: - -let - mkEmail = name: "${name}@${config.mine.shared.settings.domain}"; - - mkUserNormal = name: { - user_id = name; - member_email = mkEmail name; - mail = "env:EMAIL_${lib.toUpper name}"; - groups = [ "base_member" ]; - mail_disk_quota = 100*1024*1024; # mb - }; - - mkUserSystem = name: password_file: { - user_id = name; - member_email = mkEmail name; - password = "file:${password_file}"; - # TODO: remove base_member in the future, or have - # more granular controls for emails and shit - groups = [ "base_member" "system_service" ]; - mail_disk_quota = 10*1024*1024; # mb - }; - - mkUserAdmin = name: { - user_id = name; - member_email = mkEmail name; - groups = [ "base_member" "lldap_admin" ]; - mail_disk_quota = 100*1024*1024; # mb - }; -in { - imports = [ - ./bootstrap/lldap-state-module.nix - ]; - - mine.lldap_provision = { - enable = true; - - url = config.mine.shared.meta.lldap.url; - username = "admin"; - passwordFile = config.age.secrets.lldap-admin-user-pass.path; - # username = "testusername"; - # passwordFile = ./test.txt; - - group_attributes = { - group_foo = { - attributeType = "STRING"; - isEditable = true; - isVisible = true; - }; - }; - user_attributes = { - member_email = { - attributeType = "STRING"; - isEditable = false; - isVisible = true; - }; - mail_disk_quota = { - attributeType = "INTEGER"; - }; - }; - - groups = let - gs = [ - "base_member" - "system_service" - "system_email" - ]; - in lib.listToAttrs (lib.forEach gs (v: lib.nameValuePair v { display_name = v; })); - - users = { - # normal users - testusername = { - member_email = "env:USER1_EMAIL"; - }; - - user1 = mkUserNormal "thief420"; - - # admin users - admin = mkUserAdmin "admin"; - eyjhb = mkUserAdmin "eyjhb"; - rasmus = mkUserAdmin "rasmus"; - - # system users - authelia = mkUserSystem "authelia" config.age.secrets.authelia-smtp-password.path; - wger = mkUserSystem "wger" config.age.secrets.wger-ldap-pass.path; - - # bind user - bind_user = { - groups = [ "lldap_password_manager" "lldap_strict_readonly" ]; - }; - }; - }; - - systemd.services.lldapsetup.environment = { - USER1_EMAIL = "eyjhbbbbbbb@fricloud.dk"; - EMAIL_THIEF420 = "someemail@gmail.com"; - }; -} diff --git a/machines/gerd/services/stalwart/stalwart.nix b/machines/gerd/services/stalwart/stalwart.nix index 5a174d8..1ab1106 100644 --- a/machines/gerd/services/stalwart/stalwart.nix +++ b/machines/gerd/services/stalwart/stalwart.nix @@ -50,7 +50,10 @@ in { filter = let _mkFilter = attrs: ph: config.mine.shared.lib.ldap.mkFilter (lconfig: llib: llib.mkAnd [ - (llib.mkGroup lconfig.groups.member) + (llib.mkOr [ + (llib.mkGroup lconfig.groups.member) + (llib.mkGroup lconfig.groups.system_mail) + ]) (llib.mkOr (lib.forEach attrs (v: llib.mkSearch v ph))) ] ); @@ -58,22 +61,21 @@ in { attrs = config.mine.shared.settings.ldap.attr // { emailAlias = "mailAlias"; emailList = "mailList"; }; in { name = _mkFilter [ attrs.uid ] "?"; - email = _mkFilter [ attrs.email attrs.emailAlias attrs.emailList ] "?"; - verify = _mkFilter [ attrs.email attrs.emailAlias ] "*?*"; - expand = _mkFilter [ attrs.emailList ] "?"; - domains = _mkFilter [ attrs.email attrs.emailAlias ] "*@?"; + email = _mkFilter [ attrs.membermail ] "?"; }; - attributes = { - name = "uid"; + attributes = config.mine.shared.lib.ldap.mkScope (lconfig: llib: { + name = lconfig.attr.uid; + # name = lconfig.attr.member_mail; + description = lconfig.attr.firstname; + email = lconfig.attr.membermail; + quota = lconfig.attr.membermaildiskquota; class = "objectClass"; - description = "givenName"; - secret = "uid"; groups = "memberOf"; - email = "mail"; - # email-alias = "mailAlias"; - # quota = "diskQuota"; - }; + # we dont have access to this in lldap + # secret = lconfig.attr.stalwart_secret; + }); + }; diff --git a/machines/gerd/services/wger/default.nix b/machines/gerd/services/wger/default.nix index fa5b9cb..b1285f2 100644 --- a/machines/gerd/services/wger/default.nix +++ b/machines/gerd/services/wger/default.nix @@ -18,7 +18,7 @@ in { # wger specific settings wgerSettings = { - EMAIL_FROM = "wger Workout Manager "; + EMAIL_FROM = "wger Workout Manager "; # use authelia for authentication (disable guest users + regisration) AUTH_PROXY_HEADER = config.mine.shared.lib.authelia.protectedHeaders.username; @@ -39,7 +39,7 @@ in { EMAIL_PORT = config.mine.shared.settings.mail.ports.submissions; EMAIL_USE_SSL = true; EMAIL_HOST_USER = "wger"; - EMAIL_HOST_PASSWORD = "$EMAIL_HOST_PASSWORD"; + EMAIL_HOST_PASSWORD = "file:${config.age.secrets.wger-ldap-pass.path}"; EMAIL_FROM_ADDRESS = config.services.wger.wgerSettings.EMAIL_FROM; EMAIL_PAGE_DOMAIN = SITE_URL; }; @@ -62,6 +62,14 @@ in { locations."/api".proxyPass = "http://localhost:${builtins.toString port}"; }; + # setup lldap user for authelia that can send emails + services.lldap.provision.users = config.mine.shared.lib.ldap.mkScope (lconfig: llib: { + wger = llib.mkProvisionUserSystem "wger" config.age.secrets.wger-ldap-pass.path; + }); + + # setup permissions + age.secrets.wger-ldap-pass.owner = config.services.wger.user; + # metadata mine.shared.meta.wger = { name = "Wger"; diff --git a/machines/gerd/services/wger/wgerpkg/module.nix b/machines/gerd/services/wger/wgerpkg/module.nix index 4f69f3c..d7bcd85 100644 --- a/machines/gerd/services/wger/wgerpkg/module.nix +++ b/machines/gerd/services/wger/wgerpkg/module.nix @@ -23,6 +23,8 @@ let for k, v in json.load(f).items(): if isinstance(v, str) and v.startswith("$"): v = os.environ[v[1:]] + if isinstance(v, str) and v.startswith("file:"): + v = open(v[5:], "r").read().strip() globals()[k] = v @@ -30,6 +32,8 @@ let for k, v in json.load(f).items(): if isinstance(v, str) and v.startswith("$"): v = os.environ[v[1:]] + if isinstance(v, str) and v.startswith("file:"): + v = open(v[5:], "r").read().strip() WGER_SETTINGS[k] = v ''; diff --git a/secrets/default.nix b/secrets/default.nix index 3ac36f7..f4ff9b7 100644 --- a/secrets/default.nix +++ b/secrets/default.nix @@ -17,6 +17,7 @@ group = "secrets-lldap-bind-user-pass"; mode = "0440"; }; + lldap-user-emails-env.file = ./lldap/user-emails-env.age; lldap-bind-user-pass-hedgedoc-env.file = ./lldap/bind-user-pass-hedgedoc-env.age; # mumble diff --git a/secrets/lldap/user-emails-env.age b/secrets/lldap/user-emails-env.age new file mode 100644 index 0000000..393a671 Binary files /dev/null and b/secrets/lldap/user-emails-env.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix index e159a2f..56b3d1a 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -28,6 +28,7 @@ in "lldap/admin-user-pass.age".publicKeys = defaultAccess; "lldap/bind-user-pass.age".publicKeys = defaultAccess; "lldap/bind-user-pass-hedgedoc-env.age".publicKeys = defaultAccess; + "lldap/user-emails-env.age".publicKeys = defaultAccess; # mumble "murmur/env.age".publicKeys = defaultAccess; diff --git a/secrets/wger/env.age b/secrets/wger/env.age index c848bf6..288de08 100644 --- a/secrets/wger/env.age +++ b/secrets/wger/env.age @@ -1,11 +1,12 @@ age-encryption.org/v1 --> ssh-ed25519 QSDXqg KGoB/V0cCAZsfVmoLDmA5Xs2HOHqjg54TYqixYQduEw -sqDb6QnEbwEncAbxKLRLkjCQIwMLBTNMVcejFOwhZWM --> X25519 o64XZRaiK7ZEquTMmXTyhpdArawiuXC+5W5seFrJclY -qTLXrNGMTPAXs5EzMuCiQ07Ho2LT1KTku2f1AlCHPlk --> ssh-ed25519 n8n9DQ a8ESfbksuY++k52UJwTKJtb4/aiYzQqUgyYqfug5oyA -bZygFOW6YSg83CmZRpsNDux+UgOxCfja1eQ/R4NyLXM --> ssh-ed25519 BTp6UA yFBZAlGtHV98t6UA8QbELjOW/Pu6KYVPjbXFvijl9m0 -+eobFp5YNBsr2+10Huimwypn3S4/lc7zoX5Ldko9mhA ---- g7w825LgydJlmyZiqnIL0ofUsTn+e47rFmSG8ft6Qqg -!l:^ك}R&X^_213-ˣ0nBDK&٩D:^Uw 8(XQZs֪^(C!$(w8t!粱̈t;Ngۧ[f+قQ \ No newline at end of file +-> ssh-ed25519 QSDXqg 1g79p7fDXhx/jHR4Z6PY4MsJyITD84/bimvr0jRcgCQ +41z4XNjkwik7rdj9UdJs/ZR+gUGa+rTOXFEQz50UWlo +-> X25519 XzyBVMh7elt7LdkzGAG1qz5kiKAZIeFHJeYVhYCh+gY +cbEWc7hdQ7ddoBnFRUFYzvunIGn/tNMckaEao7Lcxw4 +-> ssh-ed25519 n8n9DQ bl0lknR3pVULG/2mRe7rtb6oFjBgr5zVayHM8Oc0dCM +gYkyO5PNrzwDMqcS5s5RnXH7kLIw5IdYB9qLzXTraX0 +-> ssh-ed25519 BTp6UA D36+NXsMYDzeqgFbMTsdTuKWgHbQUcTw0jheGX3ndmw +pTtYYl2jLimVJdGAKhRqgcBg6tpg0LOvNnY+QoRgomk +--- lsPTx+ZG4T1MFVjue9ceTeieyEI99LF0D9RNBTnZG08 + +-wfBr6H^PEÌ󨞜3B--t?nd^7c/[zfxŠ{ ji1ABۢ7* \ No newline at end of file