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