Final attempt at getting stalwart working before revert

Non working parts:

1. OIDC login, stalwart assumes the entire token is base64 encoded,
   which it is not.
2. Apparently there's no support for mixed directories, allowing both
   logins from ldap and from internal database. I want this in order
   to support accounts for services as well as persons.
This commit is contained in:
Kaare Hoff Skovgaard 2025-07-30 11:07:45 +02:00
parent 2d3e02ad78
commit fbcd590bfe
Signed by: khs
GPG key ID: C7D890804F01E9F0
8 changed files with 95 additions and 46 deletions

View file

@ -19,6 +19,7 @@ in
services.stalwart-mail.settings = { services.stalwart-mail.settings = {
certificate.default = { certificate.default = {
cert = "%{file:${acmeDir}/fullchain.pem}%"; cert = "%{file:${acmeDir}/fullchain.pem}%";
default = true;
private-key = "%{file:${config.security.acme.certs.${fqdn}.directory}/key.pem}%"; private-key = "%{file:${config.security.acme.certs.${fqdn}.directory}/key.pem}%";
}; };
}; };

View file

@ -36,8 +36,34 @@ in
enable = true; enable = true;
package = pkgs.callPackage ./package/package.nix { }; package = pkgs.callPackage ./package/package.nix { };
settings = { settings = {
config = {
local-keys =
# defaults
[
"store.*"
"directory.*"
"tracer.*"
"!server.blocked-ip.*"
"!server.allowed-ip.*"
"server.*"
"authentication.fallback-admin.*"
"cluster.*"
"config.local-keys.*"
"storage.data"
"storage.blob"
"storage.lookup"
"storage.fts"
"storage.directory"
"certificate.*"
]
# KHS addded
++ [
"http.*"
"lookup.default.*"
];
};
http = { http = {
url = "https://${fqdn}"; url = "'https://${fqdn}'";
use-x-forwarded = true; use-x-forwarded = true;
}; };
server = { server = {
@ -63,13 +89,9 @@ in
protocol = "imap"; protocol = "imap";
tls.implicit = true; tls.implicit = true;
}; };
jmap = {
bind = "[::]:8080";
url = "https://${fqdn}";
protocol = "jmap";
};
management = { management = {
bind = "[::]:8080"; bind = "[::]:8080";
url = "https://${fqdn}";
protocol = "http"; protocol = "http";
}; };
}; };
@ -78,7 +100,6 @@ in
hostname = fqdn; hostname = fqdn;
domain = "kaareskovgaard.net"; domain = "kaareskovgaard.net";
}; };
spam-filter.resource = "${config.services.stalwart-mail.package.spam-filter}/spam-filter.toml";
}; };
}; };
# TODO: Include a similiar rule for openstack # TODO: Include a similiar rule for openstack

View file

@ -213,6 +213,10 @@ in
]) cfg.domains ]) cfg.domains
); );
services.stalwart-mail.settings = { services.stalwart-mail.settings = {
config.local-keys = [
"auth.*"
"signature.*"
];
auth.dkim = { auth.dkim = {
sign = authDkim ++ [ sign = authDkim ++ [
(otherwise false) (otherwise false)

View file

@ -17,6 +17,9 @@ in
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
services.stalwart-mail.settings = { services.stalwart-mail.settings = {
config.local-keys = [
"storage.ldap.*"
];
storage = { storage = {
directory = "ldap"; directory = "ldap";
}; };

View file

@ -5,41 +5,43 @@ let
in in
{ {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
# khscodes.services.vault-agent.templates = [ services.stalwart-mail.settings = {
# { tracer.stdout.level = "trace";
# contents = '' directory.oidc = {
# {{- with secret "kanidm/data/apps/dovecot" -}} type = "oidc";
# scope = email openid profile url = "ldaps://login.kaareskovgaard.net";
# username_attribute = username timeout = "1s";
# debug = yes endpoint.url = "https://login.kaareskovgaard.net/oauth2/openid/dovecot/userinfo";
# introspection_url = https://dovecot:{{ .Data.data.basic_secret }}@login.kaareskovgaard.net/oauth2/token/introspect endpoint.method = "userinfo";
# introspection_mode = post auth.method = "user-token";
# {{- end -}} auth.username = "dovecot";
# ''; auth.secret = "%{file:${oauthConfigFile}}%";
# destination = oauthConfigFile; fields.email = "email";
# perms = "0600"; fields.username = "preferred_username";
# owner = "root"; fields.full-name = "name";
# group = "root"; };
# restartUnits = [ "dovecot2.service" ]; };
# } khscodes.services.vault-agent.templates = [
# ]; {
# services.dovecot2.extraConfig = '' contents = ''
# auth_mechanisms = $auth_mechanisms oauthbearer xoauth2 {{- with secret "kanidm/data/apps/dovecot" -}}
{{ .Data.data.basic_secret }}@login.kaareskovgaard.net/oauth2/token/introspect
# passdb { {{- end -}}
# driver = oauth2 '';
# mechanisms = xoauth2 oauthbearer destination = oauthConfigFile;
# args = ${oauthConfigFile} perms = "0600";
# } owner = "stalwart-mail";
# ''; group = "stalwart-mail";
# systemd.services.dovecot2 = { restartUnits = [ "stalwart-mail.service" ];
# serviceConfig.ReadOnlyPaths = [ }
# oauthConfigFile ];
# ]; systemd.services.stalwart-mail = {
# unitConfig.ConditionPathExists = [ serviceConfig.ReadOnlyPaths = [
# oauthConfigFile oauthConfigFile
# ]; ];
# }; unitConfig.ConditionPathExists = [
oauthConfigFile
];
};
}; };
} }

View file

@ -1,4 +1,5 @@
# This file contains patches for Nixos 25.05 to be compatible with new stalwart mail # This file contains patches for Nixos 25.05 to be compatible with new stalwart mail.
# Also some minor patches to avoid having warnings on startup
{ {
lib, lib,
config, config,
@ -10,6 +11,17 @@ let
configFile = configFormat.generate "stalwart-mail.toml" config.services.stalwart-mail.settings; configFile = configFormat.generate "stalwart-mail.toml" config.services.stalwart-mail.settings;
in in
{ {
services.stalwart-mail.settings = {
config.local-keys = [
"spam-filter.resource"
]
++ [
# I think these maybe should be added to nixpkgs?
"resolver.*"
"webadmin.*"
];
spam-filter.resource = "file://${config.services.stalwart-mail.package.spam-filter}/spam-filter.toml";
};
systemd.services.stalwart-mail = lib.mkIf config.services.stalwart-mail.enable { systemd.services.stalwart-mail = lib.mkIf config.services.stalwart-mail.enable {
serviceConfig = { serviceConfig = {
User = "stalwart-mail"; User = "stalwart-mail";
@ -18,6 +30,7 @@ in
"" ""
"${lib.getExe config.services.stalwart-mail.package} --config=${configFile}" "${lib.getExe config.services.stalwart-mail.package} --config=${configFile}"
]; ];
ReadOnlyPaths = [ "${config.services.stalwart-mail.package.spam-filter}/spam-filter.toml" ];
}; };
}; };
} }

View file

@ -5,9 +5,12 @@ let
in in
{ {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
services.stalwart-mail.settings.metrics.prometheus = { services.stalwart-mail.settings = {
config.local-keys = [ "metrics.prometheus.*" ];
metrics.prometheus = {
enable = true; enable = true;
}; };
};
# Don't expose the endpoint # Don't expose the endpoint
khscodes.services.nginx.virtualHosts."${fqdn}".locations."=/metrics/prometheus" = { khscodes.services.nginx.virtualHosts."${fqdn}".locations."=/metrics/prometheus" = {
return = 404; return = 404;

View file

@ -74,6 +74,8 @@
$config['oauth_identity_uri'] = 'https://login.kaareskovgaard.net/oauth2/openid/dovecot/userinfo'; $config['oauth_identity_uri'] = 'https://login.kaareskovgaard.net/oauth2/openid/dovecot/userinfo';
$config['oauth_identity_fields'] = ['preferred_username']; $config['oauth_identity_fields'] = ['preferred_username'];
$config['oauth_scope'] = 'email openid profile'; $config['oauth_scope'] = 'email openid profile';
# Don't show login dialog, just redirect to oauth login page
# $config['oauth_login_redirect'] = true;
''; '';
}; };
khscodes.services.nginx = { khscodes.services.nginx = {