at 25.11-pre 9.3 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.services.usbguard; 9 10 # valid policy options 11 policy = ( 12 lib.types.enum [ 13 "allow" 14 "block" 15 "reject" 16 "keep" 17 "apply-policy" 18 ] 19 ); 20 21 # decide what file to use for rules 22 ruleFile = if cfg.rules != null then pkgs.writeText "usbguard-rules" cfg.rules else cfg.ruleFile; 23 24 daemonConf = '' 25 # generated by nixos/modules/services/security/usbguard.nix 26 RuleFile=${ruleFile} 27 ImplicitPolicyTarget=${cfg.implicitPolicyTarget} 28 PresentDevicePolicy=${cfg.presentDevicePolicy} 29 PresentControllerPolicy=${cfg.presentControllerPolicy} 30 InsertedDevicePolicy=${cfg.insertedDevicePolicy} 31 RestoreControllerDeviceState=${lib.boolToString cfg.restoreControllerDeviceState} 32 # this does not seem useful for endusers to change 33 DeviceManagerBackend=uevent 34 IPCAllowedUsers=${lib.concatStringsSep " " cfg.IPCAllowedUsers} 35 IPCAllowedGroups=${lib.concatStringsSep " " cfg.IPCAllowedGroups} 36 IPCAccessControlFiles=/var/lib/usbguard/IPCAccessControl.d/ 37 DeviceRulesWithPort=${lib.boolToString cfg.deviceRulesWithPort} 38 # HACK: that way audit logs still land in the journal 39 AuditFilePath=/dev/null 40 ''; 41 42 daemonConfFile = pkgs.writeText "usbguard-daemon-conf" daemonConf; 43 44in 45{ 46 47 ###### interface 48 49 options = { 50 services.usbguard = { 51 enable = lib.mkEnableOption "USBGuard daemon"; 52 53 package = lib.mkPackageOption pkgs "usbguard" { 54 extraDescription = '' 55 If you do not need the Qt GUI, use `pkgs.usbguard-nox` to save disk space. 56 ''; 57 }; 58 59 ruleFile = lib.mkOption { 60 type = lib.types.nullOr lib.types.path; 61 default = "/var/lib/usbguard/rules.conf"; 62 example = "/run/secrets/usbguard-rules"; 63 description = '' 64 This tells the USBGuard daemon which file to load as policy rule set. 65 66 The file can be changed manually or via the IPC interface assuming it has the right file permissions. 67 68 For more details see {manpage}`usbguard-rules.conf(5)`. 69 ''; 70 71 }; 72 rules = lib.mkOption { 73 type = lib.types.nullOr lib.types.lines; 74 default = null; 75 example = '' 76 allow with-interface equals { 08:*:* } 77 ''; 78 description = '' 79 The USBGuard daemon will load this as the policy rule set. 80 As these rules are NixOS managed they are immutable and can't 81 be changed by the IPC interface. 82 83 If you do not set this option, the USBGuard daemon will load 84 it's policy rule set from the option configured in `services.usbguard.ruleFile`. 85 86 Running `usbguard generate-policy` as root will 87 generate a config for your currently plugged in devices. 88 89 For more details see {manpage}`usbguard-rules.conf(5)`. 90 ''; 91 }; 92 93 implicitPolicyTarget = lib.mkOption { 94 type = lib.types.enum [ 95 "allow" 96 "block" 97 "reject" 98 ]; 99 default = "block"; 100 description = '' 101 How to treat USB devices that don't match any rule in the policy. 102 Target should be one of allow, block or reject (logically remove the 103 device node from the system). 104 ''; 105 }; 106 107 presentDevicePolicy = lib.mkOption { 108 type = policy; 109 default = "apply-policy"; 110 description = '' 111 How to treat USB devices that are already connected when the daemon 112 starts. Policy should be one of allow, block, reject, keep (keep 113 whatever state the device is currently in) or apply-policy (evaluate 114 the rule set for every present device). 115 ''; 116 }; 117 118 presentControllerPolicy = lib.mkOption { 119 type = policy; 120 default = "keep"; 121 description = '' 122 How to treat USB controller devices that are already connected when 123 the daemon starts. One of allow, block, reject, keep or apply-policy. 124 ''; 125 }; 126 127 insertedDevicePolicy = lib.mkOption { 128 type = lib.types.enum [ 129 "block" 130 "reject" 131 "apply-policy" 132 ]; 133 default = "apply-policy"; 134 description = '' 135 How to treat USB devices that are already connected after the daemon 136 starts. One of block, reject, apply-policy. 137 ''; 138 }; 139 140 restoreControllerDeviceState = lib.mkOption { 141 type = lib.types.bool; 142 default = false; 143 description = '' 144 The USBGuard daemon modifies some attributes of controller 145 devices like the default authorization state of new child device 146 instances. Using this setting, you can control whether the daemon 147 will try to restore the attribute values to the state before 148 modification on shutdown. 149 ''; 150 }; 151 152 IPCAllowedUsers = lib.mkOption { 153 type = lib.types.listOf lib.types.str; 154 default = [ "root" ]; 155 example = [ 156 "root" 157 "yourusername" 158 ]; 159 description = '' 160 A list of usernames that the daemon will accept IPC connections from. 161 ''; 162 }; 163 164 IPCAllowedGroups = lib.mkOption { 165 type = lib.types.listOf lib.types.str; 166 default = [ ]; 167 example = [ "wheel" ]; 168 description = '' 169 A list of groupnames that the daemon will accept IPC connections 170 from. 171 ''; 172 }; 173 174 deviceRulesWithPort = lib.mkOption { 175 type = lib.types.bool; 176 default = false; 177 description = '' 178 Generate device specific rules including the "via-port" attribute. 179 ''; 180 }; 181 182 dbus.enable = lib.mkEnableOption "USBGuard dbus daemon"; 183 }; 184 }; 185 186 ###### implementation 187 188 config = lib.mkIf cfg.enable { 189 190 environment.systemPackages = [ cfg.package ]; 191 192 systemd.services = { 193 usbguard = { 194 description = "USBGuard daemon"; 195 196 wantedBy = [ "basic.target" ]; 197 wants = [ "systemd-udevd.service" ]; 198 199 # make sure an empty rule file exists 200 preStart = ''[ -f "${ruleFile}" ] || touch ${ruleFile}''; 201 202 serviceConfig = { 203 Type = "simple"; 204 ExecStart = "${cfg.package}/bin/usbguard-daemon -P -k -c ${daemonConfFile}"; 205 Restart = "on-failure"; 206 207 StateDirectory = [ 208 "usbguard" 209 "usbguard/IPCAccessControl.d" 210 ]; 211 212 AmbientCapabilities = ""; 213 CapabilityBoundingSet = "CAP_CHOWN CAP_FOWNER"; 214 DeviceAllow = "/dev/null rw"; 215 DevicePolicy = "strict"; 216 IPAddressDeny = "any"; 217 LockPersonality = true; 218 MemoryDenyWriteExecute = true; 219 NoNewPrivileges = true; 220 PrivateDevices = true; 221 PrivateTmp = true; 222 ProtectControlGroups = true; 223 ProtectHome = true; 224 ProtectKernelModules = true; 225 ProtectSystem = true; 226 ReadOnlyPaths = "-/"; 227 ReadWritePaths = "-/dev/shm -/tmp"; 228 RestrictAddressFamilies = [ 229 "AF_UNIX" 230 "AF_NETLINK" 231 ]; 232 RestrictNamespaces = true; 233 RestrictRealtime = true; 234 SystemCallArchitectures = "native"; 235 SystemCallFilter = "@system-service"; 236 UMask = "0077"; 237 }; 238 }; 239 240 usbguard-dbus = lib.mkIf cfg.dbus.enable { 241 description = "USBGuard D-Bus Service"; 242 243 wantedBy = [ "multi-user.target" ]; 244 requires = [ "usbguard.service" ]; 245 246 serviceConfig = { 247 Type = "dbus"; 248 BusName = "org.usbguard1"; 249 ExecStart = "${cfg.package}/bin/usbguard-dbus --system"; 250 Restart = "on-failure"; 251 }; 252 253 aliases = [ "dbus-org.usbguard.service" ]; 254 }; 255 }; 256 257 security.polkit.extraConfig = 258 let 259 groupCheck = 260 (lib.concatStrings (map (g: "subject.isInGroup(\"${g}\") || ") cfg.IPCAllowedGroups)) + "false"; 261 in 262 lib.optionalString cfg.dbus.enable '' 263 polkit.addRule(function(action, subject) { 264 if ((action.id == "org.usbguard.Policy1.listRules" || 265 action.id == "org.usbguard.Policy1.appendRule" || 266 action.id == "org.usbguard.Policy1.removeRule" || 267 action.id == "org.usbguard.Devices1.applyDevicePolicy" || 268 action.id == "org.usbguard.Devices1.listDevices" || 269 action.id == "org.usbguard1.getParameter" || 270 action.id == "org.usbguard1.setParameter") && 271 subject.active == true && subject.local == true && 272 (${groupCheck})) { 273 return polkit.Result.YES; 274 } 275 }); 276 ''; 277 }; 278 imports = [ 279 (lib.mkRemovedOptionModule [ "services" "usbguard" "IPCAccessControlFiles" ] 280 "The usbguard module now hardcodes IPCAccessControlFiles to /var/lib/usbguard/IPCAccessControl.d." 281 ) 282 (lib.mkRemovedOptionModule [ 283 "services" 284 "usbguard" 285 "auditFilePath" 286 ] "Removed usbguard module audit log files. Audit logs can be found in the systemd journal.") 287 (lib.mkRenamedOptionModule 288 [ "services" "usbguard" "implictPolicyTarget" ] 289 [ "services" "usbguard" "implicitPolicyTarget" ] 290 ) 291 ]; 292}