{ config, lib, # pkgs, ... }: let inherit (lib) mkIf mkEnableOption mkOption ; inherit (lib.types) str; cfg = config.services.mathebau-mail; in { options.services.mathebau-mail = { enable = mkEnableOption "mathebau mail service"; fqdn = mkOption { type = str; }; domain = mkOption { type = str; }; siteOwner = mkOption { type = str; }; }; config = mkIf cfg.enable { services = { stalwart-mail = { enable = true; openFirewall = true; settings = { # TODO TLS server = { hostname = cfg.fqdn; listener = { "smtp" = { bind = ["[::]:25"]; protocol = "smtp"; tls.implicit = false; }; "submissions" = { bind = ["[::]:465"]; protocol = "smtp"; tls.implicit = true; }; "imaptls" = { bind = ["[::]:993"]; protocol = "imap"; tls.implicit = true; }; "management" = { bind = ["127.0.0.1:8080"]; protocol = "http"; }; }; tls = { certificate = cfg.fqdn; enable = true; implicit = false; }; }; #TODO session.rcpt.relay = [ { if = "!is_empty(authenticated_as)", then = true }, { else = false } ]; queue.outbound = { # see https://stalw.art/docs/smtp/outbound/routing/ relay host example next-hop = "'relay'"; tls.mta-sts = "disable"; tls.dane = "disable"; }; remote."relay" = { address = "mailout.hrz.tu-darmstadt.de"; port = 25; protocol = "smtp"; tls.implicit = false; tls.allow-invalid-certs = false; }; /* sieve.trusted.scripts = { redirects = '' require ["envelope", "include"]; include :global "track-replies"; if envelope :is "to" "gonne@koma89.tu-darmstadt.de" { redirect "gonne@mathebau.de"; } ''; }; session.data.script = "'redirects'"; */ authentication.fallback-admin = { user = "admin"; secret = "$argon2i$v=19$m=4096,t=3,p=1$d0hYOTkzclpzSmFTZUplWnhVeWE$I7q9uB19RWL0oZKaPlMPSlGfFp6FQ/vrx80FFKCsalg"; }; }; }; }; environment.persistence.${config.impermanence.name} = { directories = [ "/var/lib/acme" # Persist TLS keys and account "/var/lib/stalwart-mail" ]; files = ["/root/.ssh/known_hosts"]; # for the backup server bragi }; security.acme.defaults.email = cfg.siteOwner; security.acme.acceptTerms = true; # Update HRZ allowlist # For account details see https://www-cgi.hrz.tu-darmstadt.de/mail/ # will stop working if no valid TUIDs are associated to our domain. /* systemd.timers."mailAllowlist" = { wantedBy = ["timers.target"]; timerConfig = { OnBootSec = "5m"; # Run every 5 minutes OnUnitActiveSec = "5m"; RandomizedDelaySec = "2m"; # prevent overload on regular intervals Unit = "mailAllowlist.service"; }; }; systemd.services."mailAllowlist" = { description = "Allowlist update: Post the mail addresses to the HRZ allowllist"; script = '' # Get the mail addresses' local-part #TODO # Post local-parts to HRZ ${pkgs.curl}/bin/curl https://www-cgi.hrz.tu-darmstadt.de/mail/whitelist-update.php -F emaildomain=${cfg.domain} -F password=$(cat /run/secrets/allowlistPass) -F emailliste=@/tmp/addresses -F meldungen=voll # Cleanup rm /tmp/addresses ''; serviceConfig = { Type = "oneshot"; User = "stalwart-mail"; NoNewPrivileges = true; # See https://www.man7.org/linux/man-pages/man5/systemd.exec.5.html PrivateTmp = true; ProtectHome = true; ReadOnlyPaths = "/"; ReadWritePaths = "/tmp"; InaccessiblePaths = "-/lost+found"; PrivateDevices = true; PrivateUsers = true; ProtectHostname = true; ProtectClock = true; ProtectKernelTunables = true; ProtectKernelModules = true; ProtectKernelLogs = true; ProtectControlGroups = true; LockPersonality = true; MemoryDenyWriteExecute = true; RestrictRealtime = true; RestrictSUIDSGID = true; }; }; */ # Backups /* services.borgbackup.jobs.mail = { paths = [ "/var/lib/stalwart-mail" ]; encryption.mode = "none"; # Otherwise the key is next to the backup or we have human interaction. environment = { BORG_RSH = "ssh -i /run/secrets/backupKey"; # “Borg ensures that backups are not created on random drives that ‘just happen’ to contain a Borg repository.” # https://borgbackup.readthedocs.io/en/stable/deployment/automated-local.html # We don't want this in order to not need to persist borg cache and simplify new deployments. BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK = "yes"; }; repo = "borg@192.168.1.11:kaluut"; # TODO for https://gitea.mathebau.de/Fachschaft/nixConfig/issues/33 startAt = "daily"; user = "root"; group = "root"; }; */ }; }