Unverified Commit 468768b9 authored by Martin Weinelt's avatar Martin Weinelt Committed by GitHub
Browse files

Reapply "nixos/dovecot: improve and harden systemd unit" (#422829)

parents a378aa50 fa949a7b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -72,6 +72,8 @@

- []{#sec-release-25.11-incompatibilities-sourcehut-removed} The `services.sourcehut` module and corresponding `sourcehut` packages were removed due to being broken and unmaintained.

- The `dovecot` systemd service was renamed from `dovecot2` to `dovecot`. The former is now just an alias. Update any overrides on the systemd unit to the new name.

- The `yeahwm` package and `services.xserver.windowManager.yeahwm` module were removed due to the package being broken and unmaintained upstream.

- The `services.postgresql` module now sets up a systemd unit `postgresql.target`. Depending on `postgresql.target` guarantees that postgres is in read-write mode and initial/ensure scripts were executed. Depending on `postgresql.service` only guarantees a read-only connection.
+70 −4
Original line number Diff line number Diff line
@@ -296,6 +296,20 @@ in

    enableLmtp = mkEnableOption "starting the LMTP listener (when Dovecot is enabled)";

    hasNewUnitName = mkOption {
      type = types.bool;
      default = true;
      readOnly = true;
      internal = true;
      description = ''
        Inspectable option to confirm that the dovecot module uses the new
        `dovecot.service` name, instead of `dovecot2.service`.

        This is a helper added for the nixos-mailserver project and can be
        removed after branching off nixos-25.11.
      '';
    };

    protocols = mkOption {
      type = types.listOf types.str;
      default = [ ];
@@ -692,23 +706,69 @@ in

    environment.etc."dovecot/dovecot.conf".source = cfg.configFile;

    systemd.services.dovecot2 = {
    systemd.services.dovecot = {
      aliases = [ "dovecot2.service" ];
      description = "Dovecot IMAP/POP3 server";
      documentation = [
        "man:dovecot(1)"
        "https://doc.dovecot.org"
      ];

      after = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];
      restartTriggers = [
        cfg.configFile
      ];
      restartTriggers = [ cfg.configFile ];

      startLimitIntervalSec = 60; # 1 min
      serviceConfig = {
        Type = "notify";
        ExecStart = "${dovecotPkg}/sbin/dovecot -F";
        ExecReload = "${dovecotPkg}/sbin/doveadm reload";

        CapabilityBoundingSet = [
          "CAP_CHOWN"
          "CAP_DAC_OVERRIDE"
          "CAP_FOWNER"
          "CAP_KILL" # Required for child process management
          "CAP_NET_BIND_SERVICE"
          "CAP_SETGID"
          "CAP_SETUID"
          "CAP_SYS_CHROOT"
          "CAP_SYS_RESOURCE"
        ];
        LockPersonality = true;
        MemoryDenyWriteExecute = true;
        NoNewPrivileges = false; # e.g for sendmail
        OOMPolicy = "continue";
        PrivateTmp = true;
        ProcSubset = "pid";
        ProtectClock = true;
        ProtectControlGroups = true;
        ProtectHome = lib.mkDefault false;
        ProtectHostname = true;
        ProtectKernelLogs = true;
        ProtectKernelModules = true;
        ProtectKernelTunables = true;
        ProtectProc = "invisible";
        ProtectSystem = "full";
        PrivateDevices = true;
        Restart = "on-failure";
        RestartSec = "1s";
        RestrictAddressFamilies = [
          "AF_INET"
          "AF_INET6"
          "AF_NETLINK" # e.g. getifaddrs in sieve handling
          "AF_UNIX"
        ];
        RestrictNamespaces = true;
        RestrictRealtime = true;
        RestrictSUIDSGID = false; # sets sgid on maildirs
        RuntimeDirectory = [ "dovecot2" ];
        SystemCallArchitectures = "native";
        SystemCallFilter = [
          "@system-service @resources"
          "~@privileged"
          "@chown @setuid capset chroot"
        ];
      };

      # When copying sieve scripts preserve the original time stamp
@@ -773,6 +833,12 @@ in
        assertion = cfg.sieve.scripts != { } -> (cfg.mailUser != null && cfg.mailGroup != null);
        message = "dovecot requires mailUser and mailGroup to be set when `sieve.scripts` is set";
      }
      {
        assertion = config.systemd.services ? dovecot2 == false;
        message = ''
          Your configuration sets options on the `dovecot2` systemd service. These have no effect until they're migrated to the `dovecot` service.
        '';
      }
    ];

  };
+3 −1
Original line number Diff line number Diff line
@@ -84,11 +84,13 @@

  testScript = ''
    machine.wait_for_unit("postfix.service")
    machine.wait_for_unit("dovecot2.service")
    machine.wait_for_unit("dovecot.service")
    machine.succeed("send-testmail")
    machine.succeed("send-lda")
    machine.wait_until_fails('[ "$(postqueue -p)" != "Mail queue is empty" ]')
    machine.succeed("test-imap")
    machine.succeed("test-pop")

    machine.log(machine.succeed("systemd-analyze security dovecot.service | grep -v ✓"))
  '';
}