diff --git a/nixos/machines/kaalut/allowlistPass.yaml b/nixos/machines/kaalut/allowlistPass.yaml new file mode 100644 index 0000000..e69de29 diff --git a/nixos/machines/kaalut/backupKey.yaml b/nixos/machines/kaalut/backupKey.yaml new file mode 100644 index 0000000..e69de29 diff --git a/nixos/machines/kaalut/configuration.nix b/nixos/machines/kaalut/configuration.nix new file mode 100644 index 0000000..35b1449 --- /dev/null +++ b/nixos/machines/kaalut/configuration.nix @@ -0,0 +1,36 @@ +{ + imports = [ + ./hardware-configuration.nix + ../../modules/mail.nix + ../../roles + ../../roles/vm.nix + ../../modules/vmNetwork.nix + ]; + + # System configuration here + + services.mathebau-mail = { + enable = true; + hostName = "mathebau.de"; + siteOwner = "root@mathebau.de"; + }; + + networking.hostName = "kaalut"; + vmNetwork.ipv4 = "192.168.0.17"; + system.stateVersion = "24.11"; + + sops.secrets = { + allowlistPass = { + sopsFile = ./allowlistPass.yaml; + owner = "stalwart-mail"; + group = "stalwart-mail"; + mode = "0400"; + }; + backupKey = { + sopsFile = ./backupKey.yaml; + owner = "stalwart-mail"; + group = "stalwart-mail"; + mode = "0400"; + }; + }; +} diff --git a/nixos/machines/kaalut/hardware-configuration.nix b/nixos/machines/kaalut/hardware-configuration.nix new file mode 100644 index 0000000..ce7112d --- /dev/null +++ b/nixos/machines/kaalut/hardware-configuration.nix @@ -0,0 +1,30 @@ +{ + lib, + pkgs, + ... +}: { + imports = []; + + fileSystems."/" = { + device = "root"; + fsType = "tmpfs"; + options = ["size=1G" "mode=755"]; + }; + fileSystems."/persist" = { + device = "/dev/disk/by-label/nixos"; + fsType = "btrfs"; + options = ["subvol=persist"]; + neededForBoot = true; + }; + fileSystems."/boot" = { + device = "/dev/disk/by-label/boot"; + fsType = "ext4"; + }; + fileSystems."/nix" = { + device = "/dev/disk/by-label/nixos"; + fsType = "btrfs"; + options = ["subvol=nix"]; + }; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/nixos/modules/mail.nix b/nixos/modules/mail.nix new file mode 100644 index 0000000..2af3f3c --- /dev/null +++ b/nixos/modules/mail.nix @@ -0,0 +1,146 @@ +# Adapted and simplified from https://nixos.wiki/wiki/Mailman +{ + config, + lib, + pkgs, + ... +}: let + inherit + (lib) + mkIf + mkEnableOption + mkOption + ; + inherit (lib.types) str; + cfg = config.services.mathebau-mailman; +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 = { + certificate."${cfg.fqdn}" = { + cert = "file://${config.security.acme.certs.${cfg.fqdn}.directory}/full.pem"; + private-key = "file://${config.security.acme.certs.${cfg.fqdn}.directory}/key.pem"; + }; + server = { + hostname = cfg.fqdn; + tls = { + certificate = cfg.fqdn; + enable = true; + implicit = false; + }; + }; + queue.outbound = { + # see https://stalw.art/docs/smtp/outbound/routing/ relay host example + next-hop = ["relay"]; + tls.mta-sts = "disable"; + tls.dane = "disable"; + }; + queue."relay" = { + address = "192.168.0.24"; #TODO mailout.hrz… + port = 25; + protocol = "smtp"; + tls.implicit = false; + tls.allow-invalid-certs = false; + }; + }; + }; + nginx.virtualHosts.${cfg.fqdn} = { + enableACME = true; # Get certificates (primarily for postfix) + forceSSL = false; # Don't use HTTPS behind the proxy + }; + }; + + 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 used by mailman 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.hostName} -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.mailman = { + 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"; + }; + }; +}