{ lib, pkgs, ... }: { services.clamav = { daemon = { enable = true; settings = { MaxThreads = 24; MaxQueue = 48; MaxFileSize = "100M"; MaxScanSize = "300M"; MaxDirectoryRecursion = 60; ExcludePath = [ "^/sys(/|$)" "^/proc(/|$)" "^/dev(/|$)" "^/run(/|$)" "^/nix/store(/|$)" ]; #CommandReadTimeout = 0; }; }; updater = { enable = true; interval = "hourly"; # Number of database checks per day used by freshclam. # Redundant if the updater is a one-shot service, though. # frequency = 24; }; scanner = { enable = true; interval = "17:15:00"; }; }; systemd.services.clamdscan.serviceConfig.ExecStart = lib.mkForce '' ${pkgs.bash}/bin/bash -c ' \ echo "Scanning directory /"; \ exec "${pkgs.clamav}/bin/clamdscan" \ --log=/var/log/clamav/scan.log \ --multiscan \ --fdpass \ --infected \ --verbose \ --file-list=<(find / \\( -path /proc -o -path /sys -o -path /dev -o -path /run -o -path /nix/store \\) -prune -o -type f -print) \ ' ''; systemd.services.clamav-daemon.serviceConfig = { LimitNOFILE = 8192; }; systemd.timers.clamdscan.timerConfig = { Persistent = true; #RandomizedDelaySec = "2h"; }; #### # ClamAV scan service #### systemd.services.clamav-scan = { #### description = "ClamAV system scan"; #### documentation = [ "man:clamscan(1)" ]; #### after = [ #### "clamav-freshclam.service" #### "local-fs.target" #### ]; #### wants = [ "clamav-freshclam.service" ]; #### script = '' #### exec ${pkgs.clamav}/bin/clamscan \ #### --infected \ #### --recursive \ #### --log=/var/log/clamav/scan.log \ #### --exclude-dir="^/sys(/|$)" \ #### --exclude-dir="^/proc(/|$)" \ #### --exclude-dir="^/dev(/|$)" \ #### --exclude-dir="^/run(/|$)" \ #### --exclude-dir="^/nix/store(/|$)" \ #### --max-filesize=100M \ #### --max-scansize=300M \ #### / #### ''; #### serviceConfig = { #### Type = "oneshot"; #### Nice = 19; #### IOSchedulingClass = "idle"; #### # clamscan returns: #### # 0 = no infection #### # 1 = infection found #### # 2 = error #### # #### # Finding malware should be recorded, but should not make systemd #### # describe the scanner itself as broken. #### SuccessExitStatus = [ 0 1 ]; #### # Creates /var/log/clamav automatically. #### LogsDirectory = "clamav"; #### LogsDirectoryMode = "0750"; #### PrivateTmp = true; #### PrivateDevices = true; #### NoNewPrivileges = true; #### ProtectSystem = "strict"; #### ProtectHome = "read-only"; #### ReadWritePaths = [ "/var/log/clamav" ]; #### ProtectKernelTunables = true; #### ProtectKernelModules = true; #### ProtectKernelLogs = true; #### ProtectControlGroups = true; #### RestrictRealtime = true; #### RestrictSUIDSGID = true; #### LockPersonality = true; #### MemoryDenyWriteExecute = true; #### SystemCallArchitectures = "native"; #### }; #### }; #### # Daily ClamAV scan timer #### systemd.timers.clamav-scan = { #### description = "Daily ClamAV scan at 10:00:00"; #### wantedBy = [ "timers.target" ]; #### timerConfig = { #### OnCalendar = "*-*-* 09:05:00"; #### Persistent = true; #### Unit = "clamav-scan.service"; #### }; #### }; #### # Systemd hardening for ClamAV daemon #### systemd.services.clamav-daemon.serviceConfig = { #### PrivateTmp = lib.mkForce true; #### ProtectSystem = "strict"; #### ProtectHome = "read-only"; #### ReadWritePaths = [ #### "/var/lib/clamav" #### "/run/clamav" #### ]; #### NoNewPrivileges = true; #### ProtectKernelTunables = true; #### ProtectKernelModules = true; #### ProtectKernelLogs = true; #### ProtectControlGroups = true; #### RestrictRealtime = true; #### RestrictSUIDSGID = true; #### LockPersonality = true; #### }; }