mailserver: update to e33fbde and add test
This commit is contained in:
parent
c7e404f8be
commit
503f1c31ea
6 changed files with 368 additions and 36 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
|
@ -16,6 +16,19 @@ Template:
|
||||||
|
|
||||||
# Upcoming Release
|
# Upcoming Release
|
||||||
|
|
||||||
|
## Breaking Changes
|
||||||
|
|
||||||
|
- Updated simple-nixos-mailserver. Update all options following this pattern:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- mailserver.mailboxes.<name>.specialUse = "value"
|
||||||
|
+ mailserver.mailboxes.<name>.special_use = "\\value"
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that simple-nixos-mailserver wanted to upgrade the location of the storage path
|
||||||
|
to include the ldap UID instead of the email but I kept the email address.
|
||||||
|
This means there is no migration to do.
|
||||||
|
|
||||||
# v0.8.0
|
# v0.8.0
|
||||||
|
|
||||||
## Breaking Changes
|
## Breaking Changes
|
||||||
|
|
|
||||||
|
|
@ -5009,6 +5009,9 @@
|
||||||
"services-mailserver-options-shb.mailserver.ssl.systemdService": [
|
"services-mailserver-options-shb.mailserver.ssl.systemdService": [
|
||||||
"services-mailserver.html#services-mailserver-options-shb.mailserver.ssl.systemdService"
|
"services-mailserver.html#services-mailserver-options-shb.mailserver.ssl.systemdService"
|
||||||
],
|
],
|
||||||
|
"services-mailserver-options-shb.mailserver.stateVersion": [
|
||||||
|
"services-mailserver.html#services-mailserver-options-shb.mailserver.stateVersion"
|
||||||
|
],
|
||||||
"services-mailserver-options-shb.mailserver.subdomain": [
|
"services-mailserver-options-shb.mailserver.subdomain": [
|
||||||
"services-mailserver.html#services-mailserver-options-shb.mailserver.subdomain"
|
"services-mailserver.html#services-mailserver-options-shb.mailserver.subdomain"
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -403,6 +403,7 @@
|
||||||
// (vm_test "homepage" ./test/services/homepage.nix)
|
// (vm_test "homepage" ./test/services/homepage.nix)
|
||||||
// (vm_test "jellyfin" ./test/services/jellyfin.nix)
|
// (vm_test "jellyfin" ./test/services/jellyfin.nix)
|
||||||
// (vm_test "karakeep" ./test/services/karakeep.nix)
|
// (vm_test "karakeep" ./test/services/karakeep.nix)
|
||||||
|
// (vm_test "mailserver" ./test/services/mailserver.nix)
|
||||||
// (vm_test "nextcloud" ./test/services/nextcloud.nix)
|
// (vm_test "nextcloud" ./test/services/nextcloud.nix)
|
||||||
// (vm_test "open-webui" ./test/services/open-webui.nix)
|
// (vm_test "open-webui" ./test/services/open-webui.nix)
|
||||||
// (vm_test "paperless" ./test/services/paperless.nix)
|
// (vm_test "paperless" ./test/services/paperless.nix)
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ in
|
||||||
builtins.fetchGit {
|
builtins.fetchGit {
|
||||||
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver.git";
|
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver.git";
|
||||||
ref = "master";
|
ref = "master";
|
||||||
rev = "7d433bf89882f61621f95082e90a4ab91eb0bdd3";
|
rev = "e33fbde199eaad513ef5d0746db19d5878150232";
|
||||||
}
|
}
|
||||||
+ "/default.nix"
|
+ "/default.nix"
|
||||||
)
|
)
|
||||||
|
|
@ -105,7 +105,7 @@ in
|
||||||
description = ''
|
description = ''
|
||||||
Accounts to sync emails from using IMAP.
|
Accounts to sync emails from using IMAP.
|
||||||
|
|
||||||
Emails will be stored under `''${config.mailserver.mailDirectory}/''${name}/''${username}`
|
Emails will be stored under `''${config.mailserver.storage.path}/''${name}/''${username}`
|
||||||
'';
|
'';
|
||||||
type = lib.types.attrsOf (
|
type = lib.types.attrsOf (
|
||||||
lib.types.submodule {
|
lib.types.submodule {
|
||||||
|
|
@ -137,7 +137,7 @@ in
|
||||||
type = lib.types.submodule {
|
type = lib.types.submodule {
|
||||||
options = shb.contracts.secret.mkRequester {
|
options = shb.contracts.secret.mkRequester {
|
||||||
mode = "0400";
|
mode = "0400";
|
||||||
owner = config.mailserver.vmailUserName;
|
owner = config.mailserver.storage.owner;
|
||||||
restartUnits = [ "mbsync.service" ];
|
restartUnits = [ "mbsync.service" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -267,7 +267,7 @@ in
|
||||||
Enabling this app will create a new LDAP configuration or update one that exists with
|
Enabling this app will create a new LDAP configuration or update one that exists with
|
||||||
the given host.
|
the given host.
|
||||||
'';
|
'';
|
||||||
default = { };
|
default = null;
|
||||||
type = lib.types.nullOr (
|
type = lib.types.nullOr (
|
||||||
lib.types.submodule {
|
lib.types.submodule {
|
||||||
options = {
|
options = {
|
||||||
|
|
@ -333,6 +333,26 @@ in
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
stateVersion = lib.mkOption {
|
||||||
|
type = lib.types.ints.positive;
|
||||||
|
# SHB started at stateVersion 3.
|
||||||
|
default = 4;
|
||||||
|
description = ''
|
||||||
|
Tracking stateful version changes as an incrementing number.
|
||||||
|
|
||||||
|
When a new release comes out we may require manual migration steps to
|
||||||
|
be completed, before the new version can be put into production.
|
||||||
|
|
||||||
|
If your `stateVersion` is too low one or multiple assertions may
|
||||||
|
trigger to give you instructions on what migrations steps are required
|
||||||
|
to continue. Increase the `stateVersion` as instructed by the assertion
|
||||||
|
message.
|
||||||
|
|
||||||
|
See https://nixos-mailserver.readthedocs.io/en/latest/release-notes.html
|
||||||
|
and https://nixos-mailserver.readthedocs.io/en/latest/migrations.html
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
backup = lib.mkOption {
|
backup = lib.mkOption {
|
||||||
description = ''
|
description = ''
|
||||||
Backup emails, index and sieve.
|
Backup emails, index and sieve.
|
||||||
|
|
@ -340,16 +360,16 @@ in
|
||||||
default = { };
|
default = { };
|
||||||
type = lib.types.submodule {
|
type = lib.types.submodule {
|
||||||
options = shb.contracts.backup.mkRequester {
|
options = shb.contracts.backup.mkRequester {
|
||||||
user = config.mailserver.vmailUserName;
|
user = config.mailserver.storage.owner;
|
||||||
sourceDirectories = builtins.filter (x: x != null) [
|
sourceDirectories = builtins.filter (x: x != null) [
|
||||||
config.mailserver.indexDir
|
config.mailserver.indexDir
|
||||||
config.mailserver.mailDirectory
|
config.mailserver.storage.path
|
||||||
config.mailserver.sieveDirectory
|
config.mailserver.sieveDirectory
|
||||||
];
|
];
|
||||||
sourceDirectoriesText = ''
|
sourceDirectoriesText = ''
|
||||||
[
|
[
|
||||||
config.mailserver.indexDir
|
config.mailserver.indexDir
|
||||||
config.mailserver.mailDirectory
|
config.mailserver.storage.path
|
||||||
config.mailserver.sieveDirectory
|
config.mailserver.sieveDirectory
|
||||||
]
|
]
|
||||||
'';
|
'';
|
||||||
|
|
@ -367,7 +387,7 @@ in
|
||||||
user = config.services.rspamd.user;
|
user = config.services.rspamd.user;
|
||||||
userText = "services.rspamd.user";
|
userText = "services.rspamd.user";
|
||||||
sourceDirectories = builtins.filter (x: x != null) [
|
sourceDirectories = builtins.filter (x: x != null) [
|
||||||
config.mailserver.dkimKeyDirectory
|
config.mailserver.dkim.keyDirectory
|
||||||
];
|
];
|
||||||
sourceDirectoriesText = ''
|
sourceDirectoriesText = ''
|
||||||
[
|
[
|
||||||
|
|
@ -385,14 +405,14 @@ in
|
||||||
type = lib.types.attrsOf lib.types.str;
|
type = lib.types.attrsOf lib.types.str;
|
||||||
default = {
|
default = {
|
||||||
index = config.mailserver.indexDir;
|
index = config.mailserver.indexDir;
|
||||||
mail = config.mailserver.mailDirectory;
|
mail = config.mailserver.storage.path;
|
||||||
sieve = config.mailserver.sieveDirectory;
|
sieve = config.mailserver.sieveDirectory;
|
||||||
dkim = config.mailserver.dkimKeyDirectory;
|
dkim = config.mailserver.dkimKeyDirectory;
|
||||||
};
|
};
|
||||||
defaultText = lib.literalExpression ''
|
defaultText = lib.literalExpression ''
|
||||||
{
|
{
|
||||||
index = config.mailserver.indexDir;
|
index = config.mailserver.indexDir;
|
||||||
mail = config.mailserver.mailDirectory;
|
mail = config.mailserver.storage.path;
|
||||||
sieve = config.mailserver.sieveDirectory;
|
sieve = config.mailserver.sieveDirectory;
|
||||||
dkim = config.mailserver.dkimKeyDirectory;
|
dkim = config.mailserver.dkimKeyDirectory;
|
||||||
}
|
}
|
||||||
|
|
@ -417,8 +437,8 @@ in
|
||||||
(lib.mkIf cfg.enable {
|
(lib.mkIf cfg.enable {
|
||||||
mailserver = {
|
mailserver = {
|
||||||
enable = true;
|
enable = true;
|
||||||
stateVersion = 3;
|
|
||||||
fqdn = "${cfg.subdomain}.${cfg.domain}";
|
fqdn = "${cfg.subdomain}.${cfg.domain}";
|
||||||
|
inherit (cfg) stateVersion;
|
||||||
domains = [ cfg.domain ];
|
domains = [ cfg.domain ];
|
||||||
|
|
||||||
localDnsResolver = false;
|
localDnsResolver = false;
|
||||||
|
|
@ -433,18 +453,22 @@ in
|
||||||
# Using / is needed for iOS mail.
|
# Using / is needed for iOS mail.
|
||||||
# Both following options are used to organize subfolders in subdirectories.
|
# Both following options are used to organize subfolders in subdirectories.
|
||||||
hierarchySeparator = "/";
|
hierarchySeparator = "/";
|
||||||
useFsLayout = true;
|
storage = {
|
||||||
|
directoryLayout = "fs";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.postfix.config = {
|
services.postfix.settings.main = {
|
||||||
smtpd_tls_security_level = lib.mkForce "encrypt";
|
smtpd_tls_security_level = lib.mkForce "encrypt";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Is probably needed for iOS mail.
|
# Is probably needed for iOS mail.
|
||||||
services.dovecot2.extraConfig = ''
|
services.dovecot2.settings = {
|
||||||
ssl_min_protocol = TLSv1.2
|
ssl_min_protocol = "TLSv1.2";
|
||||||
ssl_cipher_list = HIGH:!aNULL:!MD5
|
# This conflicts with the default setting which seems much better than this one.
|
||||||
'';
|
# So I'm leaving the default settings and we'll see if something breaks.
|
||||||
|
# ssl_cipher_list = "HIGH:!aNULL:!MD5";
|
||||||
|
};
|
||||||
|
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
@ -482,6 +506,8 @@ in
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
forceSSL = true; # Redirect HTTP → HTTPS
|
forceSSL = true; # Redirect HTTP → HTTPS
|
||||||
|
sslCertificate = cfg.ssl.paths.cert;
|
||||||
|
sslCertificateKey = cfg.ssl.paths.key;
|
||||||
root = "/var/www"; # Dummy root
|
root = "/var/www"; # Dummy root
|
||||||
locations."/.well-known/autoconfig/mail/" = {
|
locations."/.well-known/autoconfig/mail/" = {
|
||||||
alias = "${announce}/";
|
alias = "${announce}/";
|
||||||
|
|
@ -501,6 +527,8 @@ in
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
forceSSL = true; # Redirect HTTP → HTTPS
|
forceSSL = true; # Redirect HTTP → HTTPS
|
||||||
|
sslCertificate = cfg.ssl.paths.cert;
|
||||||
|
sslCertificateKey = cfg.ssl.paths.key;
|
||||||
root = "/var/www"; # Dummy root
|
root = "/var/www"; # Dummy root
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
alias = "${landingPage}/";
|
alias = "${landingPage}/";
|
||||||
|
|
@ -548,37 +576,44 @@ in
|
||||||
uris = [
|
uris = [
|
||||||
"ldap://${cfg.ldap.host}:${toString cfg.ldap.port}"
|
"ldap://${cfg.ldap.host}:${toString cfg.ldap.port}"
|
||||||
];
|
];
|
||||||
searchBase = "ou=people,${cfg.ldap.dcdomain}";
|
base = "ou=people,${cfg.ldap.dcdomain}";
|
||||||
searchScope = "sub";
|
scope = "sub";
|
||||||
bind = {
|
bind = {
|
||||||
dn = "uid=${cfg.ldap.adminName},ou=people,${cfg.ldap.dcdomain}";
|
dn = "uid=${cfg.ldap.adminName},ou=people,${cfg.ldap.dcdomain}";
|
||||||
passwordFile = cfg.ldap.adminPassword.result.path;
|
passwordFile = cfg.ldap.adminPassword.result.path;
|
||||||
};
|
};
|
||||||
# Note that nixos simple mailserver sets auth_bind=yes
|
|
||||||
# which means authentication binds are used.
|
|
||||||
# https://doc.dovecot.org/2.3/configuration_manual/authentication/ldap_bind/#authentication-ldap-bind
|
|
||||||
dovecot =
|
dovecot =
|
||||||
let
|
let
|
||||||
filter = "(&(objectClass=inetOrgPerson)(mail=%{user})(memberOf=cn=${cfg.ldap.userGroup},ou=groups,${cfg.ldap.dcdomain}))";
|
filter = "(&(objectClass=inetOrgPerson)(mail=%{user})(memberOf=cn=${cfg.ldap.userGroup},ou=groups,${cfg.ldap.dcdomain}))";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
passAttrs = "user=user";
|
|
||||||
passFilter = filter;
|
passFilter = filter;
|
||||||
userAttrs = lib.concatStringsSep "," [
|
|
||||||
"=home=${config.mailserver.mailDirectory}/${cfg.ldap.account}/%u"
|
|
||||||
# "mail=maildir:${config.mailserver.mailDirectory}/${cfg.ldap.account}/%u/mail"
|
|
||||||
"uid=${config.mailserver.vmailUserName}"
|
|
||||||
"gid=${config.mailserver.vmailGroupName}"
|
|
||||||
];
|
|
||||||
userFilter = filter;
|
userFilter = filter;
|
||||||
};
|
};
|
||||||
|
# username needs to be set to mail so postfix maps correctly the mail address.
|
||||||
|
# Otherwise we get error messages when sending
|
||||||
|
# Sender address rejected: not owned by user
|
||||||
|
attributes = {
|
||||||
|
username = "mail";
|
||||||
|
};
|
||||||
postfix = {
|
postfix = {
|
||||||
filter = "(&(objectClass=inetOrgPerson)(mail=%s)(memberOf=cn=${cfg.ldap.userGroup},ou=groups,${cfg.ldap.dcdomain}))";
|
filter = "(&(objectClass=inetOrgPerson)(mail=%s)(memberOf=cn=${cfg.ldap.userGroup},ou=groups,${cfg.ldap.dcdomain}))";
|
||||||
mailAttribute = "mail";
|
|
||||||
uidAttribute = "mail";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
services.dovecot2.settings = {
|
||||||
|
"userdb ldap" = {
|
||||||
|
fields.home = lib.mkForce "${config.mailserver.storage.path}/${cfg.ldap.account}/%{user}";
|
||||||
|
fields.mail_index_path = lib.mkForce "${config.mailserver.storage.path}/${cfg.ldap.account}/%{user}";
|
||||||
|
};
|
||||||
|
"passdb ldap" = {
|
||||||
|
# LLDAP does not understand ldap user password setup.
|
||||||
|
fields.password = lib.mkForce null;
|
||||||
|
# We use bind DN auth.
|
||||||
|
# https://doc.dovecot.org/2.3/configuration_manual/authentication/ldap_bind/#authentication-ldap-bind
|
||||||
|
bind = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
})
|
})
|
||||||
(lib.mkIf (cfg.enable && cfg.imapSync != null) {
|
(lib.mkIf (cfg.enable && cfg.imapSync != null) {
|
||||||
systemd.services.mbsync =
|
systemd.services.mbsync =
|
||||||
|
|
@ -601,11 +636,11 @@ in
|
||||||
Account ${name}
|
Account ${name}
|
||||||
|
|
||||||
MaildirStore ${name}-local
|
MaildirStore ${name}-local
|
||||||
INBOX ${config.mailserver.mailDirectory}/${name}/${acct.username}/mail/
|
INBOX ${config.mailserver.storage.path}/${name}/${acct.username}/mail/
|
||||||
# Maps subfolders on far side to actual subfolders on disk.
|
# Maps subfolders on far side to actual subfolders on disk.
|
||||||
# The other option is Maildir++ but then the mailserver.hierarchySeparator must be set to a dot '.'
|
# The other option is Maildir++ but then the mailserver.hierarchySeparator must be set to a dot '.'
|
||||||
SubFolders Verbatim
|
SubFolders Verbatim
|
||||||
Path ${config.mailserver.mailDirectory}/${name}/${acct.username}/mail/
|
Path ${config.mailserver.storage.path}/${name}/${acct.username}/mail/
|
||||||
|
|
||||||
Channel ${name}-main
|
Channel ${name}-main
|
||||||
Far :${name}-remote:
|
Far :${name}-remote:
|
||||||
|
|
@ -672,7 +707,7 @@ in
|
||||||
description = "Sync mailbox";
|
description = "Sync mailbox";
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
User = config.mailserver.vmailUserName;
|
User = config.mailserver.storage.owner;
|
||||||
};
|
};
|
||||||
script =
|
script =
|
||||||
let
|
let
|
||||||
|
|
@ -689,8 +724,8 @@ in
|
||||||
name: acct:
|
name: acct:
|
||||||
# The equal sign makes sure parent directories have the corret user and group too.
|
# The equal sign makes sure parent directories have the corret user and group too.
|
||||||
[
|
[
|
||||||
"d '${config.mailserver.mailDirectory}/${name}' 0750 ${config.mailserver.vmailUserName} ${config.mailserver.vmailGroupName} - -"
|
"d '${config.mailserver.storage.path}/${name}' 0750 ${config.mailserver.storage.owner} ${config.mailserver.storage.group} - -"
|
||||||
"d '${config.mailserver.mailDirectory}/${name}/${acct.username}' 0750 ${config.mailserver.vmailUserName} ${config.mailserver.vmailGroupName} - -"
|
"d '${config.mailserver.storage.path}/${name}/${acct.username}' 0750 ${config.mailserver.storage.owner} ${config.mailserver.storage.group} - -"
|
||||||
];
|
];
|
||||||
in
|
in
|
||||||
lib.flatten (lib.mapAttrsToList mkAccount cfg.imapSync.accounts);
|
lib.flatten (lib.mapAttrsToList mkAccount cfg.imapSync.accounts);
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,8 @@ in
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
With the example above, the mails are stored under `/var/vmail/fastmail/<email address>`.
|
||||||
|
|
||||||
### Secrets {#services-mailserver-usage-secrets}
|
### Secrets {#services-mailserver-usage-secrets}
|
||||||
|
|
||||||
Secrets can be randomly generated with `nix run nixpkgs#openssl -- rand -hex 64`.
|
Secrets can be randomly generated with `nix run nixpkgs#openssl -- rand -hex 64`.
|
||||||
|
|
|
||||||
278
test/services/mailserver.nix
Normal file
278
test/services/mailserver.nix
Normal file
|
|
@ -0,0 +1,278 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
shb,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
domain = "example.com";
|
||||||
|
subdomain = "imap";
|
||||||
|
fqdn = "${subdomain}.${domain}";
|
||||||
|
|
||||||
|
trySendMail = pkgs.writeShellApplication {
|
||||||
|
name = "trySendMail";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.swaks
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
USER="''${1:-}"
|
||||||
|
PASSWORD="''${2:-}"
|
||||||
|
|
||||||
|
if [ -z "$USER" ]; then
|
||||||
|
echo "No user given"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$PASSWORD" ]; then
|
||||||
|
swaks \
|
||||||
|
--server ${fqdn} \
|
||||||
|
--port 465 \
|
||||||
|
--tls-on-connect \
|
||||||
|
--from "$USER" \
|
||||||
|
--to "$USER"
|
||||||
|
else
|
||||||
|
swaks \
|
||||||
|
--server ${fqdn} \
|
||||||
|
--port 465 \
|
||||||
|
--tls-on-connect \
|
||||||
|
--auth LOGIN \
|
||||||
|
--auth-user "$USER" \
|
||||||
|
--auth-password "$PASSWORD" \
|
||||||
|
--from "$USER" \
|
||||||
|
--to "$USER"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
tryRcvMail = pkgs.writeShellApplication {
|
||||||
|
name = "tryRcvMail";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.curl
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
USER="''${1:-}"
|
||||||
|
PASSWORD="''${2:-}"
|
||||||
|
|
||||||
|
if [ -z "$USER" ]; then
|
||||||
|
echo "No user given"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$PASSWORD" ]; then
|
||||||
|
echo "No password given"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -s --url "imaps://imap.example.com/INBOX;UID=1" \
|
||||||
|
--user "$USER:$PASSWORD"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
basic = shb.test.runNixOSTest {
|
||||||
|
name = "mailserver_basic";
|
||||||
|
|
||||||
|
# Connect to the running VM started with driverInteractive:
|
||||||
|
# ssh-keygen -R 'vsock-mux//run/user/1000/tmpcf3hs4yp/server_host.socket'; ssh -o User=root vsock-mux//run/user/1000/tmpcf3hs4yp/server_host.socket
|
||||||
|
interactive.sshBackdoor.enable = true;
|
||||||
|
|
||||||
|
nodes.server =
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../../modules/blocks/ssl.nix
|
||||||
|
../../modules/services/mailserver.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.hosts = {
|
||||||
|
"127.0.0.1" = [ fqdn ];
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.certs.cas.selfsigned.myca = {
|
||||||
|
name = "My CA";
|
||||||
|
};
|
||||||
|
shb.certs.certs.selfsigned = {
|
||||||
|
${domain} = {
|
||||||
|
ca = config.shb.certs.cas.selfsigned.myca;
|
||||||
|
|
||||||
|
domain = "*.${domain}";
|
||||||
|
group = "nginx";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.mailserver = {
|
||||||
|
enable = true;
|
||||||
|
inherit subdomain domain;
|
||||||
|
stateVersion = 4;
|
||||||
|
ssl = config.shb.certs.certs.selfsigned.${domain};
|
||||||
|
|
||||||
|
# imapSync = {
|
||||||
|
# # syncTimer = "10s";
|
||||||
|
# # debug = false;
|
||||||
|
# # accounts.fastmail = {
|
||||||
|
# # host = "imap.fastmail.com";
|
||||||
|
# # port = 993;
|
||||||
|
# # username = email;
|
||||||
|
# # password.result = config.shb.sops.secret."mailserver/imap/fastmail/password".result;
|
||||||
|
# # mapSpecialJunk = "Spam";
|
||||||
|
# # };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# smtpRelay = {
|
||||||
|
# host = "smtp.fastmail.com";
|
||||||
|
# port = 587;
|
||||||
|
# username = email;
|
||||||
|
# password.result = config.shb.sops.secret."mailserver/smtp/fastmail/password".result;
|
||||||
|
# };
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
mailserver.mailboxes = {
|
||||||
|
Junk = {
|
||||||
|
auto = "subscribe";
|
||||||
|
special_use = "\\Junk";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
pkgs.openssl
|
||||||
|
pkgs.swaks
|
||||||
|
trySendMail
|
||||||
|
tryRcvMail
|
||||||
|
];
|
||||||
|
|
||||||
|
specialisation = {
|
||||||
|
ldap.configuration =
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../../modules/blocks/hardcodedsecret.nix
|
||||||
|
../../modules/blocks/lldap.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.hosts = {
|
||||||
|
"127.0.0.1" = [ "ldap.${domain}" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
pkgs.openldap
|
||||||
|
];
|
||||||
|
|
||||||
|
shb.hardcodedsecret.ldapUserPassword = {
|
||||||
|
request = config.shb.lldap.ldapUserPassword.request;
|
||||||
|
settings.content = "ldapUserPassword";
|
||||||
|
};
|
||||||
|
shb.hardcodedsecret.jwtSecret = {
|
||||||
|
request = config.shb.lldap.jwtSecret.request;
|
||||||
|
settings.content = "jwtSecrets";
|
||||||
|
};
|
||||||
|
shb.hardcodedsecret.alice = {
|
||||||
|
request = config.shb.lldap.ensureUsers.alice.password.request;
|
||||||
|
settings.content = "alicePassword";
|
||||||
|
};
|
||||||
|
shb.hardcodedsecret.charlie = {
|
||||||
|
request = config.shb.lldap.ensureUsers.charlie.password.request;
|
||||||
|
settings.content = "charliePassword";
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.lldap = {
|
||||||
|
enable = true;
|
||||||
|
inherit domain;
|
||||||
|
subdomain = "ldap";
|
||||||
|
ldapPort = 3890;
|
||||||
|
webUIListenPort = 17170;
|
||||||
|
dcdomain = "dc=example,dc=com";
|
||||||
|
ldapUserPassword.result = config.shb.hardcodedsecret.ldapUserPassword.result;
|
||||||
|
jwtSecret.result = config.shb.hardcodedsecret.jwtSecret.result;
|
||||||
|
debug = true;
|
||||||
|
|
||||||
|
ensureUsers = {
|
||||||
|
alice = {
|
||||||
|
email = "alice@example.com";
|
||||||
|
groups = [ "user_group" ];
|
||||||
|
password.result = config.shb.hardcodedsecret.alice.result;
|
||||||
|
};
|
||||||
|
charlie = {
|
||||||
|
email = "charlie@example.com";
|
||||||
|
groups = [ "other_group" ];
|
||||||
|
password.result = config.shb.hardcodedsecret.charlie.result;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ensureGroups = {
|
||||||
|
user_group = { };
|
||||||
|
admin_group = { };
|
||||||
|
other_group = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.mailserver = {
|
||||||
|
ldap = {
|
||||||
|
enable = true;
|
||||||
|
host = "127.0.0.1";
|
||||||
|
port = config.shb.lldap.ldapPort;
|
||||||
|
dcdomain = config.shb.lldap.dcdomain;
|
||||||
|
adminName = "admin";
|
||||||
|
adminPassword.result = config.shb.hardcodedsecret.ldapUserPassword.result;
|
||||||
|
account = "fastmail";
|
||||||
|
userGroup = "user_group";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript =
|
||||||
|
{ nodes, ... }:
|
||||||
|
let
|
||||||
|
specialisations = "${nodes.server.system.build.toplevel}/specialisation";
|
||||||
|
switch = name: "${specialisations}/${name}/bin/switch-to-configuration test";
|
||||||
|
|
||||||
|
ldapSearch =
|
||||||
|
let
|
||||||
|
config = nodes.server.specialisation.ldap.configuration;
|
||||||
|
in
|
||||||
|
lib.concatStringsSep " " [
|
||||||
|
"ldapsearch"
|
||||||
|
"-H ldap://ldap.example.com:${toString config.shb.lldap.ldapPort}"
|
||||||
|
];
|
||||||
|
ldapSearchAdmin =
|
||||||
|
let
|
||||||
|
config = nodes.server.specialisation.ldap.configuration;
|
||||||
|
in
|
||||||
|
lib.concatStringsSep " " [
|
||||||
|
"ldapsearch"
|
||||||
|
"-H ldap://ldap.example.com:${toString config.shb.lldap.ldapPort}"
|
||||||
|
"-D uid=admin,ou=people,${config.shb.lldap.dcdomain}"
|
||||||
|
"-w ${config.shb.hardcodedsecret.ldapUserPassword.settings.content}"
|
||||||
|
];
|
||||||
|
in
|
||||||
|
''
|
||||||
|
server.wait_for_unit("multi-user.target")
|
||||||
|
server.wait_for_unit("dovecot")
|
||||||
|
|
||||||
|
with subtest("ldap"):
|
||||||
|
server.succeed("${switch "ldap"}")
|
||||||
|
|
||||||
|
server.wait_for_unit("lldap")
|
||||||
|
print(server.succeed("${ldapSearch} -LLL -D uid=alice,ou=people,dc=example,dc=com -w alicePassword -b cn=user_group,ou=groups,dc=example,dc=com | grep uniquemember | grep alice"))
|
||||||
|
print(server.succeed("${ldapSearchAdmin} -LLL -b cn=user_group,ou=groups,dc=example,dc=com | grep uniquemember | grep alice"))
|
||||||
|
|
||||||
|
server.wait_for_unit("dovecot")
|
||||||
|
print(server.fail("doveadm auth test auser@example.com apassword"))
|
||||||
|
print(server.fail("doveadm auth test charlie@example.com charliePassword"))
|
||||||
|
print(server.succeed("doveadm auth test alice@example.com alicePassword"))
|
||||||
|
|
||||||
|
server.wait_for_unit("postfix")
|
||||||
|
print(server.fail("trySendMail alice@example.com"))
|
||||||
|
print(server.fail("trySendMail auser@example.com apassword"))
|
||||||
|
print(server.fail("trySendMail charlie@example.com charliePassword"))
|
||||||
|
print(server.succeed("trySendMail alice@example.com alicePassword"))
|
||||||
|
|
||||||
|
print(server.fail("tryRcvMail charlie@example.com charliePassword"))
|
||||||
|
print(server.succeed("tryRcvMail alice@example.com alicePassword"))
|
||||||
|
|
||||||
|
print(server.succeed("find /var/vmail"))
|
||||||
|
print(server.succeed("find /var/vmail/fastmail/alice@example.com"))
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue