summary refs log tree commit diff
diff options
context:
space:
mode:
authorRobert Schütz <dev@schuetz-co.de>2021-05-03 18:52:55 +0200
committerRobert Schütz <dev@schuetz-co.de>2021-05-04 17:43:26 +0200
commit762be5c86d51b192831855f6c27de9f910c6d2b8 (patch)
treed657dfd798468997ba8c04cf77a4c94771bafdb9
parent022c5b0922b393cf9784d2d8d76e065b5de607c5 (diff)
downloadnixpkgs-762be5c86d51b192831855f6c27de9f910c6d2b8.tar
nixpkgs-762be5c86d51b192831855f6c27de9f910c6d2b8.tar.gz
nixpkgs-762be5c86d51b192831855f6c27de9f910c6d2b8.tar.bz2
nixpkgs-762be5c86d51b192831855f6c27de9f910c6d2b8.tar.lz
nixpkgs-762be5c86d51b192831855f6c27de9f910c6d2b8.tar.xz
nixpkgs-762be5c86d51b192831855f6c27de9f910c6d2b8.tar.zst
nixpkgs-762be5c86d51b192831855f6c27de9f910c6d2b8.zip
nixos/radicale: harden systemd unit
-rw-r--r--nixos/doc/manual/release-notes/rl-2105.xml7
-rw-r--r--nixos/modules/services/networking/radicale.nix47
-rw-r--r--nixos/tests/radicale.nix5
3 files changed, 51 insertions, 8 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2105.xml b/nixos/doc/manual/release-notes/rl-2105.xml
index 4aadd417a09..68dde82c18e 100644
--- a/nixos/doc/manual/release-notes/rl-2105.xml
+++ b/nixos/doc/manual/release-notes/rl-2105.xml
@@ -721,6 +721,13 @@ environment.systemPackages = [
      automatically based on <option>system.stateVersion</option>, the latest
      version is always used because old versions are not officially supported.
     </para>
+    <para>
+     Furthermore, Radicale's systemd unit was hardened which might break some
+     deployments.  In particular, a non-default
+     <literal>filesystem_folder</literal> has to be added to
+     <option>systemd.services.radicale.serviceConfig.ReadWritePaths</option> if
+     the deprecated <option>services.radicale.config</option> is used.
+    </para>
    </listitem>
   </itemizedlist>
  </section>
diff --git a/nixos/modules/services/networking/radicale.nix b/nixos/modules/services/networking/radicale.nix
index 17a42abc0b7..8c632c319d3 100644
--- a/nixos/modules/services/networking/radicale.nix
+++ b/nixos/modules/services/networking/radicale.nix
@@ -21,6 +21,8 @@ let
 
   rightsFile = format.generate "radicale.rights" cfg.rights;
 
+  bindLocalhost = cfg.settings != { } && !hasAttrByPath [ "server" "hosts" ] cfg.settings;
+
 in {
   options.services.radicale = {
     enable = mkEnableOption "Radicale CalDAV and CardDAV server";
@@ -138,15 +140,9 @@ in {
 
     environment.systemPackages = [ pkg ];
 
-    users.users.radicale =
-      { uid = config.ids.uids.radicale;
-        description = "radicale user";
-        home = "/var/lib/radicale";
-        createHome = true;
-      };
+    users.users.radicale.uid = config.ids.uids.radicale;
 
-    users.groups.radicale =
-      { gid = config.ids.gids.radicale; };
+    users.groups.radicale.gid = config.ids.gids.radicale;
 
     systemd.services.radicale = {
       description = "A Simple Calendar and Contact Server";
@@ -161,6 +157,41 @@ in {
         ));
         User = "radicale";
         Group = "radicale";
+        StateDirectory = "radicale/collections";
+        StateDirectoryMode = "0750";
+        # Hardening
+        CapabilityBoundingSet = [ "" ];
+        DeviceAllow = [ "/dev/stdin" ];
+        DevicePolicy = "strict";
+        IPAddressAllow = mkIf bindLocalhost "localhost";
+        IPAddressDeny = mkIf bindLocalhost "any";
+        LockPersonality = true;
+        MemoryDenyWriteExecute = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateTmp = true;
+        PrivateUsers = true;
+        ProcSubset = "pid";
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectProc = "invisible";
+        ProtectSystem = "strict";
+        ReadWritePaths = lib.optional
+          (hasAttrByPath [ "storage" "filesystem_folder" ] cfg.settings)
+          cfg.settings.storage.filesystem_folder;
+        RemoveIPC = true;
+        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        SystemCallArchitectures = "native";
+        SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
+        UMask = "0027";
       };
     };
   };
diff --git a/nixos/tests/radicale.nix b/nixos/tests/radicale.nix
index 8fa71898ee7..5101628a682 100644
--- a/nixos/tests/radicale.nix
+++ b/nixos/tests/radicale.nix
@@ -86,5 +86,10 @@ in {
 
     with subtest("Test web interface"):
         machine.succeed("curl --fail http://${user}:${password}@localhost:${port}/.web/")
+
+    with subtest("Test security"):
+        output = machine.succeed("systemd-analyze security radicale.service")
+        machine.log(output)
+        assert output[-9:-1] == "SAFE :-}"
   '';
 })