Merge branch 'ldap-local-coex' into 'master'
ldap: allow coexistence with local accounts See merge request simple-nixos-mailserver/nixos-mailserver!502
This commit is contained in:
@@ -70,8 +70,6 @@ SNM branch corresponding to your NixOS version.
|
||||
* [ ] [Mobileconfig](https://support.apple.com/guide/profile-manager/distribute-profiles-manually-pmdbd71ebc9/mac)
|
||||
* Improve the Forwarding Experience
|
||||
* [ ] Support [ARC](https://en.wikipedia.org/wiki/Authenticated_Received_Chain) signing with [Rspamd](https://rspamd.com/doc/modules/arc.html)
|
||||
* User management
|
||||
* [ ] Allow local and LDAP user to coexist
|
||||
* OpenID Connect
|
||||
* Depends on relevant clients adding support, e.g. [Thunderbird](https://bugzilla.mozilla.org/show_bug.cgi?id=1602166)
|
||||
|
||||
|
||||
+20
-19
@@ -649,7 +649,7 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
extraVirtualAliases = mkOption {
|
||||
aliases = mkOption {
|
||||
type =
|
||||
let
|
||||
loginAccount = mkOptionType {
|
||||
@@ -660,7 +660,6 @@ in
|
||||
with types;
|
||||
attrsOf (either loginAccount (nonEmptyListOf loginAccount));
|
||||
example = {
|
||||
"info@example.com" = "user1@example.com";
|
||||
"postmaster@example.com" = "user1@example.com";
|
||||
"abuse@example.com" = "user1@example.com";
|
||||
"multi@example.com" = [
|
||||
@@ -669,15 +668,14 @@ in
|
||||
];
|
||||
};
|
||||
description = ''
|
||||
Virtual Aliases. A virtual alias `"info@example.com" = "user1@example.com"` means that
|
||||
all mail to `info@example.com` is forwarded to `user1@example.com`. Note
|
||||
that it is expected that `postmaster@example.com` and `abuse@example.com` is
|
||||
forwarded to some valid email address. (Alternatively you can create login
|
||||
accounts for `postmaster` and (or) `abuse`). Furthermore, it also allows
|
||||
the user `user1@example.com` to send emails as `info@example.com`.
|
||||
It's also possible to create an alias for multiple accounts. In this
|
||||
example all mails for `multi@example.com` will be forwarded to both
|
||||
`user1@example.com` and `user2@example.com`.
|
||||
Aliases are additional mail addresses routed to one or more existing local accounts.
|
||||
|
||||
The target accounts are allowed to use the alias as the sender address.
|
||||
|
||||
:::{note}
|
||||
This feature is limited to local accounts and does not support LDAP or
|
||||
other external accounts.
|
||||
:::
|
||||
'';
|
||||
default = { };
|
||||
};
|
||||
@@ -685,16 +683,18 @@ in
|
||||
forwards = mkOption {
|
||||
type = with types; attrsOf (either (listOf str) str);
|
||||
example = {
|
||||
"user@example.com" = "user@elsewhere.com";
|
||||
"user@example.com" = "user@example.edu";
|
||||
"gamenight@example.com" = [
|
||||
"bob@example.com"
|
||||
"frank@example.org"
|
||||
"wendy@example.net"
|
||||
];
|
||||
};
|
||||
description = ''
|
||||
To forward mails to an external address. For instance,
|
||||
the value `{ "user@example.com" = "user@elsewhere.com"; }`
|
||||
means that mails to `user@example.com` are forwarded to
|
||||
`user@elsewhere.com`. The difference with the
|
||||
{option}`mailserver.extraVirtualAliases` option is that `user@elsewhere.com`
|
||||
can't send mail as `user@example.com`. Also, this option
|
||||
allows to forward mails to external addresses.
|
||||
Forwards route mail from local addresses to one or more local or external addresses.
|
||||
|
||||
Unlike {option}`mailserver.aliases`, the target addresses cannot send
|
||||
mail using the forward address.
|
||||
'';
|
||||
default = { };
|
||||
};
|
||||
@@ -1681,5 +1681,6 @@ in
|
||||
[ "mailserver" "ldap" "postfix" "mailAttribute" ]
|
||||
[ "mailserver" "ldap" "attributes" "mail" ]
|
||||
)
|
||||
(mkRenamedOptionModule [ "mailserver" "extraVirtualAliases" ] [ "mailserver" "aliases" ])
|
||||
];
|
||||
}
|
||||
|
||||
+21
-9
@@ -40,15 +40,25 @@ follow best practices to simplify maintenance.
|
||||
Limitations
|
||||
~~~~~~~~~~~
|
||||
|
||||
We have various assertions in place, that prevent using LDAP together with
|
||||
other features. Most of them are not technical limitations per se, but instead
|
||||
lack configuration or validation.
|
||||
Design choices
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
- Local users (:option:`mailserver.loginAccounts`) and aliases
|
||||
(:option:`mailserver.extraVirtualAliases`) are not currently allowed with
|
||||
:option:`mailserver.ldap.enable` enabled
|
||||
- Aliases based on LDAP attributes are currently not implemented
|
||||
- Quotas based on LDAP attributes are currently not implemented
|
||||
These are intentional choices in how the mail server operates that affect the
|
||||
LDAP integration.
|
||||
|
||||
- For mail address routing local accounts always take priority over LDAP accounts.
|
||||
|
||||
Planned
|
||||
^^^^^^^
|
||||
|
||||
These are features we are interested in but require implementation,
|
||||
documentation and tests.
|
||||
|
||||
- Aliases based on LDAP attributes
|
||||
- Quotas based on LDAP attributes
|
||||
|
||||
Avoided
|
||||
^^^^^^^
|
||||
|
||||
The following features will likely never be implemented, since they would
|
||||
complicate the setup significantly.
|
||||
@@ -58,7 +68,9 @@ complicate the setup significantly.
|
||||
- Use of ``homeDirectory``, ``uid``, ``gid`` LDAP attributes (we are
|
||||
committed to a virtual setup with one vmail user/uid/gid and UUID based home
|
||||
directories)
|
||||
|
||||
- Declarative aliases through :option:`mailserver.aliases`. These are limited
|
||||
to local accounts, because Postfix enforces sender ownership based on login
|
||||
identity and does not consult virtual aliases for authorization.
|
||||
|
||||
Enabling LDAP support
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -30,6 +30,8 @@ NixOS 26.05
|
||||
rather than their email address, which is more convenient and consistent
|
||||
with typical LDAP practices. The exact attribute can be customized through
|
||||
:option:`mailserver.ldap.attributes.username`.
|
||||
- Local and LDAP accounts can now co-exist. For overlapping names and addresses
|
||||
the local account will always win.
|
||||
- The following integrations are deprecated and will be removed before the next
|
||||
release:
|
||||
|
||||
|
||||
@@ -98,16 +98,6 @@ in
|
||||
) config.mailserver.dkim.domains
|
||||
)
|
||||
)
|
||||
++ lib.optionals config.mailserver.ldap.enable [
|
||||
{
|
||||
assertion = config.mailserver.loginAccounts == { };
|
||||
message = "When the LDAP support is enable (mailserver.ldap.enable = true), it is not possible to define mailserver.loginAccounts";
|
||||
}
|
||||
{
|
||||
assertion = config.mailserver.extraVirtualAliases == { };
|
||||
message = "When the LDAP support is enable (mailserver.ldap.enable = true), it is not possible to define mailserver.extraVirtualAliases";
|
||||
}
|
||||
]
|
||||
++
|
||||
lib.optionals (config.mailserver.ldap.enable && config.mailserver.mailDirectory != "/var/vmail")
|
||||
[
|
||||
|
||||
@@ -94,7 +94,7 @@ let
|
||||
mergeLookupTables lookupTables;
|
||||
|
||||
# extra_valiases_postfix :: Map String [String]
|
||||
extra_valiases_postfix = attrsToLookupTable cfg.extraVirtualAliases;
|
||||
extra_valiases_postfix = attrsToLookupTable cfg.aliases;
|
||||
|
||||
# forwards :: Map String [String]
|
||||
forwards = attrsToLookupTable cfg.forwards;
|
||||
|
||||
+2
-2
@@ -85,7 +85,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
extraVirtualAliases = {
|
||||
aliases = {
|
||||
"single-alias@example.com" = "user1@example.com";
|
||||
"multi-alias@example.com" = [
|
||||
"user1@example.com"
|
||||
@@ -494,7 +494,7 @@
|
||||
# if this succeeds, it means that user1 received the mail that was intended for chuck.
|
||||
client.fail("fetchmail --nosslcertck -v")
|
||||
|
||||
with subtest("extraVirtualAliases"):
|
||||
with subtest("Test sending from alias address (mailserver.aliases)"):
|
||||
client.execute("rm ~/mail/*")
|
||||
# send email from single-alias to user1
|
||||
client.succeed(
|
||||
|
||||
@@ -1,7 +1,25 @@
|
||||
{
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
hashPassword =
|
||||
password:
|
||||
pkgs.runCommand "password-${password}-hashed"
|
||||
{
|
||||
buildInputs = [ pkgs.mkpasswd ];
|
||||
inherit password;
|
||||
}
|
||||
''
|
||||
mkpasswd -s <<<"$password" > $out
|
||||
'';
|
||||
|
||||
bindPassword = "unsafegibberish";
|
||||
alicePassword = "testalice";
|
||||
bobPassword = "testbob";
|
||||
carolPassword = "testcarol";
|
||||
frankPassword = "testfrank";
|
||||
malloryPassword = "testmallory";
|
||||
in
|
||||
{
|
||||
name = "ldap";
|
||||
@@ -83,6 +101,22 @@ in
|
||||
mail: bob@example.com
|
||||
homeDirectory: /home/bob
|
||||
userPassword: ${bobPassword}
|
||||
|
||||
dn: cn=carol,ou=users,dc=example
|
||||
entryUUID: 41240499-27e2-4fa2-be4f-4113a77661b1
|
||||
objectClass: inetOrgPerson
|
||||
uid: carol
|
||||
sn: Baz
|
||||
mail: carol@example.com
|
||||
userPassword: ${carolPassword}
|
||||
|
||||
dn: cn=frank,ou=users,dc=example
|
||||
entryUUID: ca16f594-f6b2-418f-87d3-0d02d746461f
|
||||
objectClass: inetOrgPerson
|
||||
uid: frank
|
||||
sn: Moo
|
||||
mail: frank@example.com
|
||||
userPassword: ${frankPassword}
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -93,6 +127,24 @@ in
|
||||
localDnsResolver = false;
|
||||
indexDir = "/var/lib/dovecot/indices";
|
||||
|
||||
aliases = {
|
||||
# Steal frank@example.com from LDAP user frank
|
||||
"frank@example.com" = "mallory@example.com";
|
||||
};
|
||||
|
||||
loginAccounts = {
|
||||
# Colliding local account takes precedence over LDAP account with
|
||||
# same address.
|
||||
"carol@example.com" = {
|
||||
hashedPasswordFile = hashPassword carolPassword;
|
||||
};
|
||||
# Another account used as a virtual alias target to steal
|
||||
# frank@example.com from the LDAP user frank
|
||||
"mallory@example.com" = {
|
||||
hashedPasswordFile = hashPassword malloryPassword;
|
||||
};
|
||||
};
|
||||
|
||||
ldap = {
|
||||
enable = true;
|
||||
uris = [
|
||||
@@ -237,5 +289,37 @@ in
|
||||
]))
|
||||
machine.succeed("journalctl -u postfix | grep -q 'Sender address rejected: not owned by user bob'")
|
||||
|
||||
with subtest("Local addresses take priority over those learnt from LDAP"):
|
||||
# carol@example.com is routed to the local user account
|
||||
machine.succeed(" ".join([
|
||||
"mail-check send-and-read",
|
||||
"--smtp-port 465",
|
||||
"--smtp-ssl",
|
||||
"--smtp-host localhost",
|
||||
"--smtp-username alice", # LDAP user
|
||||
"--imap-host localhost",
|
||||
"--imap-username carol@example.com", # Local user
|
||||
"--from-addr alice@example.com",
|
||||
"--to-addr carol@example.com",
|
||||
"--src-password-file <(echo '${alicePassword}')",
|
||||
"--dst-password-file <(echo '${carolPassword}')",
|
||||
"--ignore-dkim-spf"
|
||||
]))
|
||||
|
||||
# frank@example.com gets routed to mallory@example.com due to a virtual alias
|
||||
machine.succeed(" ".join([
|
||||
"mail-check send-and-read",
|
||||
"--smtp-port 465",
|
||||
"--smtp-ssl",
|
||||
"--smtp-host localhost",
|
||||
"--smtp-username alice", # LDAP user
|
||||
"--imap-host localhost",
|
||||
"--imap-username mallory@example.com", # Local user
|
||||
"--from-addr alice@example.com",
|
||||
"--to-addr frank@example.com",
|
||||
"--src-password-file <(echo '${alicePassword}')",
|
||||
"--dst-password-file <(echo '${malloryPassword}')",
|
||||
"--ignore-dkim-spf"
|
||||
]))
|
||||
'';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user