# Adapted and simplified from https://nixos.wiki/wiki/Mailman { config, lib, pkgs, ... }: let inherit (lib) mkIf mkEnableOption mkOption ; inherit (lib.types) nonEmptyStr; cfg = config.services.mathebau-mailman; in { options.services.mathebau-mailman = { enable = mkEnableOption "mathebau mailman service"; hostName = mkOption { type = nonEmptyStr; }; siteOwner = mkOption { type = nonEmptyStr; }; }; config = mkIf cfg.enable { services = { postfix = { enable = true; relayDomains = ["hash:/var/lib/mailman/data/postfix_domains"]; config = { transport_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"]; local_recipient_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"]; proxy_interfaces = "130.83.2.184"; smtputf8_enable = "no"; # HRZ does not know SMTPUTF8 }; relayHost = "mathebau.de"; # Relay to mail vm which relays to HRZ (see https://www.hrz.tu-darmstadt.de/services/it_services/email_infrastruktur/index.de.jsp) }; mailman = { enable = true; inherit (cfg) siteOwner; hyperkitty.enable = true; webHosts = [cfg.hostName]; serve.enable = true; # # Don't include confirmation tokens in reply addresses, because we would need to send them to HRZ otherwise. settings.mta.verp_confirmations = "no"; }; }; environment.persistence.${config.impermanence.name} = { directories = [ "/var/lib/mailman" "/var/lib/mailman-web" ]; files = ["/root/.ssh/known_hosts"]; # for the backup server bragi }; networking.firewall.allowedTCPPorts = [25 80]; # 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 = "1h"; # Run every hour OnUnitActiveSec = "1h"; RandomizedDelaySec = "10m"; # prevent overload on regular intervals Unit = "mailAllowlist.service"; }; }; systemd.services."mailAllowlist" = { description = "Allowlist update: Post the mail addresses used by mailman to the HRZ allowllist"; script = '' # Get the mail addresses' local-part cut -d '@' -f 1 /var/lib/mailman/data/postfix_lmtp | grep -v '#' | grep "\S" > /tmp/addresses # Post local-parts to HRZ ${pkgs.curl}/bin/curl https://www-cgi.hrz.tu-darmstadt.de/mail/whitelist-update.php -F emaildomain=${cfg.hostName} -F password=$(cat /run/secrets/allowlistPass) -F emailliste=@/tmp/addresses -F meldungen=voll # Cleanup rm /tmp/addresses ''; serviceConfig = { Type = "oneshot"; User = "mailman"; 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.mailman = { paths = [ "/var/lib/mailman/data" "/var/lib/mailman-web" ]; 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:lobon"; # TODO for https://gitea.mathebau.de/Fachschaft/nixConfig/issues/33 startAt = "daily"; user = "root"; group = "root"; }; }; }