Begin preparing to move LDAP accounts into passdb only
This should allow LDAP accounts to have password set in LDAP, as well as provisioning service accounts statically in nix. This will also move alias configuration of all accounts into nix as well.
This commit is contained in:
parent
cc1ab841c2
commit
02325a7017
2 changed files with 158 additions and 40 deletions
128
nix/modules/nixos/infrastructure/mailserver/accounts.nix
Normal file
128
nix/modules/nixos/infrastructure/mailserver/accounts.nix
Normal file
|
@ -0,0 +1,128 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.khscodes.infrastructure.mailserver;
|
||||
accountOption = lib.khscodes.mkSubmodule {
|
||||
description = "mail account";
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "user1@example.com";
|
||||
description = "Username";
|
||||
};
|
||||
|
||||
aliases = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
example = [
|
||||
"abuse@example.com"
|
||||
"postmaster@example.com"
|
||||
];
|
||||
default = [ ];
|
||||
description = ''
|
||||
A list of aliases of this login account.
|
||||
Note: Use list entries like "@example.com" to create a catchAll
|
||||
that allows sending from all email addresses in these domain.
|
||||
'';
|
||||
};
|
||||
|
||||
aliasesRegexp = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
example = [ ''/^tom\..*@domain\.com$/'' ];
|
||||
default = [ ];
|
||||
description = ''
|
||||
Same as {option}`mailserver.aliases` but using PCRE (Perl compatible regex).
|
||||
'';
|
||||
};
|
||||
|
||||
catchAll = lib.typs.mkOption {
|
||||
type = lib.types.listOf (lib.types.enum config.mailserver.domains);
|
||||
example = [
|
||||
"example.com"
|
||||
"example2.com"
|
||||
];
|
||||
default = [ ];
|
||||
description = ''
|
||||
For which domains should this account act as a catch all?
|
||||
Note: Does not allow sending from all addresses of these domains.
|
||||
'';
|
||||
};
|
||||
|
||||
quota = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "2G";
|
||||
description = ''
|
||||
Per user quota rules. Accepted sizes are `xx k/M/G/T` with the
|
||||
obvious meaning. Leave blank for the standard quota `100G`.
|
||||
'';
|
||||
};
|
||||
|
||||
sieveScript = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.lines;
|
||||
default = null;
|
||||
example = ''
|
||||
require ["fileinto", "mailbox"];
|
||||
|
||||
if address :is "from" "gitlab@mg.gitlab.com" {
|
||||
fileinto :create "GitLab";
|
||||
stop;
|
||||
}
|
||||
|
||||
# This must be the last rule, it will check if list-id is set, and
|
||||
# file the message into the Lists folder for further investigation
|
||||
elsif header :matches "list-id" "<?*>" {
|
||||
fileinto :create "Lists";
|
||||
stop;
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Per-user sieve script.
|
||||
'';
|
||||
};
|
||||
|
||||
sendOnly = lib.types.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Specifies if the account should be a send-only account.
|
||||
Emails sent to send-only accounts will be rejected from
|
||||
unauthorized senders with the `sendOnlyRejectMessage`
|
||||
stating the reason.
|
||||
'';
|
||||
};
|
||||
|
||||
sendOnlyRejectMessage = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "This account cannot receive emails.";
|
||||
description = ''
|
||||
The message that will be returned to the sender when an email is
|
||||
sent to a send-only account. Only used if the account is marked
|
||||
as send-only.
|
||||
'';
|
||||
};
|
||||
|
||||
isLdapAccount = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Marks the account as an LDAP account. Non LDAP accounts gets passwords provisioned, such that other services can use them";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemAccounts = lib.attrsets.foldlAttrs (
|
||||
acc: name: value:
|
||||
if value.isLdapAccount then acc else acc ++ [ name ]
|
||||
) [ ] cfg.accounts;
|
||||
in
|
||||
{
|
||||
options.khscodes.infrastructure.mailserver.accounts = lib.mkOption {
|
||||
type = lib.types.attrsOf accountOption;
|
||||
default = { };
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
};
|
||||
}
|
|
@ -1,7 +1,12 @@
|
|||
{ lib, config, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.khscodes.infrastructure.mailserver;
|
||||
secretFile = "/run/secret/dovecot/ldap";
|
||||
secretFile = "/run/secret/dovecot/dovecot-ldap.conf.ext";
|
||||
in
|
||||
{
|
||||
options.khscodes.infrastructure.mailserver = {
|
||||
|
@ -16,45 +21,20 @@ in
|
|||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
mailserver.ldap = {
|
||||
enable = true;
|
||||
uris = [ "ldaps://login.kaareskovgaard.net" ];
|
||||
searchBase = "dc=login,dc=kaareskovgaard,dc=net";
|
||||
searchScope = "sub";
|
||||
bind = {
|
||||
dn = "dn=token";
|
||||
passwordFile = secretFile;
|
||||
};
|
||||
dovecot = {
|
||||
# Map LDAP uid to dovecot user, and ldap userPassword to dovecot password
|
||||
passAttrs = "uid=user";
|
||||
passFilter = "(&(class=account)(memberOf=mail_user)(uid=%u))";
|
||||
# This filter is used both when receiving mail (thus needing to lookup by mail address, and when authenticating, requriing the lookup by uid.)
|
||||
# Note that the pass filter only allows looking up by uid, so should still only be able to authenticate using that.
|
||||
userFilter = "(&(class=account)(memberOf=mail_user)(|(mail=%u)(uid=%u)))";
|
||||
userAttrs = "uid=user";
|
||||
};
|
||||
postfix = {
|
||||
filter = "(&(class=account)(memberOf=mail_user)(mail=%s))";
|
||||
mailAttribute = "uid";
|
||||
uidAttribute = "uid";
|
||||
};
|
||||
};
|
||||
services.dovecot2.extraConfig = ''
|
||||
passdb {
|
||||
driver = ldap
|
||||
args = ${secretFile}
|
||||
}
|
||||
'';
|
||||
systemd.services = {
|
||||
dovecot2 = {
|
||||
unitConfig = {
|
||||
ConditionPathExists = [ secretFile ];
|
||||
};
|
||||
};
|
||||
postfix = {
|
||||
unitConfig = {
|
||||
ConditionPathExists = [ secretFile ];
|
||||
};
|
||||
};
|
||||
postfix-setup = {
|
||||
unitConfig = {
|
||||
ConditionPathExists = [ secretFile ];
|
||||
};
|
||||
serviceConfig.ReadOnlyPaths = [
|
||||
secretFile
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -62,15 +42,25 @@ in
|
|||
{
|
||||
contents = ''
|
||||
{{- with secret "${cfg.ldap.mount}/data/${cfg.ldap.path}" -}}
|
||||
{{ .Data.data.apiToken }}
|
||||
ldap_version = 3
|
||||
uris = ldaps://login.kaareskovgaard.net
|
||||
|
||||
tls_require_cert = hard
|
||||
tls_ca_cert_file = ${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
|
||||
dn = dn=token
|
||||
dnpass = {{ .Data.data.apiToken }}
|
||||
auth_bind = yes
|
||||
base = dc=login,dc=kaareskovgaard,dc=net
|
||||
scope = subtree
|
||||
pass_attrs = uid=user
|
||||
pass_filter = (&(class=account)(memberOf=mail_user)(uid=%u)
|
||||
{{- end -}}
|
||||
'';
|
||||
destination = secretFile;
|
||||
owner = "dovecot";
|
||||
group = "dovecot";
|
||||
owner = "root";
|
||||
group = "root";
|
||||
restartUnits = [
|
||||
"dovecot2.service"
|
||||
"postfix.service"
|
||||
];
|
||||
}
|
||||
];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue