From 01d0b0b6834022a5d61a09c0013715c7aeb6be9f Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Mon, 2 Sep 2024 18:30:59 +0200 Subject: [PATCH] nixos/logrotate: harden systemd unit Logrotate is a service that runs as root and moves logfiles around while keeping ownership of these files intact. This means we can and should severely limit the scope of what can be done during its runtime. --- nixos/modules/services/logging/logrotate.nix | 51 ++++++++++++++++++-- nixos/tests/logrotate.nix | 2 + 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix index 6db1b108cc6c..6fb5f0588d97 100644 --- a/nixos/modules/services/logging/logrotate.nix +++ b/nixos/modules/services/logging/logrotate.nix @@ -97,6 +97,8 @@ in defaultText = lib.literalExpression "cfg.settings != {}"; }; + allowNetworking = lib.mkEnableOption "network access for logrotate"; + settings = lib.mkOption { default = { }; description = '' @@ -240,12 +242,55 @@ in config = lib.mkIf cfg.enable { systemd.services.logrotate = { description = "Logrotate Service"; + documentation = [ + "man:logrotate(8)" + "man:logrotate(5)" + ]; startAt = "hourly"; serviceConfig = { - Restart = "no"; - User = "root"; - ExecStart = "${pkgs.logrotate}/sbin/logrotate ${utils.escapeSystemdExecArgs cfg.extraArgs} ${mailOption} ${cfg.configFile}"; + Type = "oneshot"; + ExecStart = "${lib.getExe pkgs.logrotate} ${utils.escapeSystemdExecArgs cfg.extraArgs} ${mailOption} ${cfg.configFile}"; + + # performance + Nice = 19; + IOSchedulingClass = "best-effort"; + IOSchedulingPriority = 7; + + # hardening + CapabilityBoundingSet = [ + "CAP_CHOWN" + "CAP_SETGID" + ]; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "full"; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged @resources" + "@chown" + ]; + UMask = "0027"; + } // lib.optionalAttrs (!cfg.allowNetworking) { + PrivateNetwork = true; + RestrictAddressFamilies = "none"; }; }; systemd.services.logrotate-checkconf = { diff --git a/nixos/tests/logrotate.nix b/nixos/tests/logrotate.nix index f9c5e9060970..8d5887abec94 100644 --- a/nixos/tests/logrotate.nix +++ b/nixos/tests/logrotate.nix @@ -127,5 +127,7 @@ import ./make-test-python.nix ({ pkgs, ... }: rec { if info["ActiveState"] != "failed": raise Exception('logrotate-checkconf.service was not failed') + machine.log(machine.execute("systemd-analyze security logrotate.service | grep -v ✓")[1]) + ''; })