lldap: automatic provision + system users + stalwart + whatever
This commit is contained in:
parent
4a0129585a
commit
82caf96d36
19 changed files with 405 additions and 285 deletions
|
@ -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;
|
||||
|
|
|
@ -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}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
|
||||
#[instrument(skip_all, level = "debug")]
|
||||
async fn do_extended_request(&mut self, request: &LdapExtendedRequest) -> Vec<LdapOp> {
|
||||
- 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 = {
|
||||
|
|
|
@ -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(
|
|
@ -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)
|
||||
|
|
@ -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(
|
166
machines/gerd/services/lldap/module/default.nix
Normal file
166
machines/gerd/services/lldap/module/default.nix
Normal file
|
@ -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}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
68
machines/gerd/services/lldap/provision.nix
Normal file
68
machines/gerd/services/lldap/provision.nix
Normal file
|
@ -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;
|
||||
}
|
|
@ -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";
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ in {
|
|||
|
||||
# wger specific settings
|
||||
wgerSettings = {
|
||||
EMAIL_FROM = "wger Workout Manager <wger@${svc_domain}>";
|
||||
EMAIL_FROM = "wger Workout Manager <wger@${config.mine.shared.settings.domain}>";
|
||||
|
||||
# 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";
|
||||
|
|
|
@ -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
|
||||
'';
|
||||
|
|
|
@ -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
|
||||
|
|
BIN
secrets/lldap/user-emails-env.age
Normal file
BIN
secrets/lldap/user-emails-env.age
Normal file
Binary file not shown.
|
@ -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;
|
||||
|
|
|
@ -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·-éŒË£0ÅnBþ–<C3BE>DK€æ&Ù©Dþ:¾^½ÒUwÃÌóŸ
8(£‡ä X‡¾QZsÖªŒ<C2AA>â^(CÂ!ÍìÊ$ ™Üöý×(‹wÎ8t“ô¾<C3B4>Ñ!Úç²±Ð̈ït;¥ÃNgÚÛ§ˆ<C2A7>Ž[²f+Ù‚Q°
|
||||
-> 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
|
||||
ÿƒ¨
|
||||
-¾w¶ðf²Brî6Îö´ßH^»»ÇõÄéPÉEÌ󨞜¬ßà3×B-áû-‚ót?³nd^ë7¬có/[z‡f˜xŠëû÷{ ji1A°BŸÛ¢7Âø*ú
|
Loading…
Add table
Add a link
Reference in a new issue