at 23.11-pre 7.2 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4let 5 cfg = config.services.usbguard; 6 7 # valid policy options 8 policy = (types.enum [ "allow" "block" "reject" "keep" "apply-policy" ]); 9 10 defaultRuleFile = "/var/lib/usbguard/rules.conf"; 11 12 # decide what file to use for rules 13 ruleFile = if cfg.rules != null then pkgs.writeText "usbguard-rules" cfg.rules else defaultRuleFile; 14 15 daemonConf = '' 16 # generated by nixos/modules/services/security/usbguard.nix 17 RuleFile=${ruleFile} 18 ImplicitPolicyTarget=${cfg.implictPolicyTarget} 19 PresentDevicePolicy=${cfg.presentDevicePolicy} 20 PresentControllerPolicy=${cfg.presentControllerPolicy} 21 InsertedDevicePolicy=${cfg.insertedDevicePolicy} 22 RestoreControllerDeviceState=${boolToString cfg.restoreControllerDeviceState} 23 # this does not seem useful for endusers to change 24 DeviceManagerBackend=uevent 25 IPCAllowedUsers=${concatStringsSep " " cfg.IPCAllowedUsers} 26 IPCAllowedGroups=${concatStringsSep " " cfg.IPCAllowedGroups} 27 IPCAccessControlFiles=/var/lib/usbguard/IPCAccessControl.d/ 28 DeviceRulesWithPort=${boolToString cfg.deviceRulesWithPort} 29 # HACK: that way audit logs still land in the journal 30 AuditFilePath=/dev/null 31 ''; 32 33 daemonConfFile = pkgs.writeText "usbguard-daemon-conf" daemonConf; 34 35in 36{ 37 38 ###### interface 39 40 options = { 41 services.usbguard = { 42 enable = mkEnableOption (lib.mdDoc "USBGuard daemon"); 43 44 package = mkOption { 45 type = types.package; 46 default = pkgs.usbguard; 47 defaultText = literalExpression "pkgs.usbguard"; 48 description = lib.mdDoc '' 49 The usbguard package to use. If you do not need the Qt GUI, use 50 `pkgs.usbguard-nox` to save disk space. 51 ''; 52 }; 53 54 rules = mkOption { 55 type = types.nullOr types.lines; 56 default = null; 57 example = '' 58 allow with-interface equals { 08:*:* } 59 ''; 60 description = lib.mdDoc '' 61 The USBGuard daemon will load this as the policy rule set. 62 As these rules are NixOS managed they are immutable and can't 63 be changed by the IPC interface. 64 65 If you do not set this option, the USBGuard daemon will load 66 it's policy rule set from `${defaultRuleFile}`. 67 This file can be changed manually or via the IPC interface. 68 69 Running `usbguard generate-policy` as root will 70 generate a config for your currently plugged in devices. 71 72 For more details see {manpage}`usbguard-rules.conf(5)`. 73 ''; 74 }; 75 76 implictPolicyTarget = mkOption { 77 type = policy; 78 default = "block"; 79 description = lib.mdDoc '' 80 How to treat USB devices that don't match any rule in the policy. 81 Target should be one of allow, block or reject (logically remove the 82 device node from the system). 83 ''; 84 }; 85 86 presentDevicePolicy = mkOption { 87 type = policy; 88 default = "apply-policy"; 89 description = lib.mdDoc '' 90 How to treat USB devices that are already connected when the daemon 91 starts. Policy should be one of allow, block, reject, keep (keep 92 whatever state the device is currently in) or apply-policy (evaluate 93 the rule set for every present device). 94 ''; 95 }; 96 97 presentControllerPolicy = mkOption { 98 type = policy; 99 default = "keep"; 100 description = lib.mdDoc '' 101 How to treat USB controller devices that are already connected when 102 the daemon starts. One of allow, block, reject, keep or apply-policy. 103 ''; 104 }; 105 106 insertedDevicePolicy = mkOption { 107 type = policy; 108 default = "apply-policy"; 109 description = lib.mdDoc '' 110 How to treat USB devices that are already connected after the daemon 111 starts. One of block, reject, apply-policy. 112 ''; 113 }; 114 115 restoreControllerDeviceState = mkOption { 116 type = types.bool; 117 default = false; 118 description = lib.mdDoc '' 119 The USBGuard daemon modifies some attributes of controller 120 devices like the default authorization state of new child device 121 instances. Using this setting, you can control whether the daemon 122 will try to restore the attribute values to the state before 123 modification on shutdown. 124 ''; 125 }; 126 127 IPCAllowedUsers = mkOption { 128 type = types.listOf types.str; 129 default = [ "root" ]; 130 example = [ "root" "yourusername" ]; 131 description = lib.mdDoc '' 132 A list of usernames that the daemon will accept IPC connections from. 133 ''; 134 }; 135 136 IPCAllowedGroups = mkOption { 137 type = types.listOf types.str; 138 default = [ ]; 139 example = [ "wheel" ]; 140 description = lib.mdDoc '' 141 A list of groupnames that the daemon will accept IPC connections 142 from. 143 ''; 144 }; 145 146 deviceRulesWithPort = mkOption { 147 type = types.bool; 148 default = false; 149 description = lib.mdDoc '' 150 Generate device specific rules including the "via-port" attribute. 151 ''; 152 }; 153 }; 154 }; 155 156 157 ###### implementation 158 159 config = mkIf cfg.enable { 160 161 environment.systemPackages = [ cfg.package ]; 162 163 systemd.services.usbguard = { 164 description = "USBGuard daemon"; 165 166 wantedBy = [ "basic.target" ]; 167 wants = [ "systemd-udevd.service" ]; 168 169 # make sure an empty rule file exists 170 preStart = ''[ -f "${ruleFile}" ] || touch ${ruleFile}''; 171 172 serviceConfig = { 173 Type = "simple"; 174 ExecStart = "${cfg.package}/bin/usbguard-daemon -P -k -c ${daemonConfFile}"; 175 Restart = "on-failure"; 176 177 StateDirectory = [ 178 "usbguard" 179 "usbguard/IPCAccessControl.d" 180 ]; 181 182 AmbientCapabilities = ""; 183 CapabilityBoundingSet = "CAP_CHOWN CAP_FOWNER"; 184 DeviceAllow = "/dev/null rw"; 185 DevicePolicy = "strict"; 186 IPAddressDeny = "any"; 187 LockPersonality = true; 188 MemoryDenyWriteExecute = true; 189 NoNewPrivileges = true; 190 PrivateDevices = true; 191 PrivateTmp = true; 192 ProtectControlGroups = true; 193 ProtectHome = true; 194 ProtectKernelModules = true; 195 ProtectSystem = true; 196 ReadOnlyPaths = "-/"; 197 ReadWritePaths = "-/dev/shm -/tmp"; 198 RestrictAddressFamilies = [ "AF_UNIX" "AF_NETLINK" ]; 199 RestrictNamespaces = true; 200 RestrictRealtime = true; 201 SystemCallArchitectures = "native"; 202 SystemCallFilter = "@system-service"; 203 UMask = "0077"; 204 }; 205 }; 206 }; 207 imports = [ 208 (mkRemovedOptionModule [ "services" "usbguard" "ruleFile" ] "The usbguard module now uses ${defaultRuleFile} as ruleFile. Alternatively, use services.usbguard.rules to configure rules.") 209 (mkRemovedOptionModule [ "services" "usbguard" "IPCAccessControlFiles" ] "The usbguard module now hardcodes IPCAccessControlFiles to /var/lib/usbguard/IPCAccessControl.d.") 210 (mkRemovedOptionModule [ "services" "usbguard" "auditFilePath" ] "Removed usbguard module audit log files. Audit logs can be found in the systemd journal.") 211 ]; 212}