1 { config, lib, pkgs, ... }:
5 cfg = config.services.usbguard;
8 policy = (types.enum [ "allow" "block" "reject" "keep" "apply-policy" ]);
10 # decide what file to use for rules
11 ruleFile = if cfg.rules != null then pkgs.writeText "usbguard-rules" cfg.rules else cfg.ruleFile;
14 # generated by nixos/modules/services/security/usbguard.nix
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
31 daemonConfFile = pkgs.writeText "usbguard-daemon-conf" daemonConf;
40 enable = mkEnableOption "USBGuard daemon";
42 package = mkPackageOption pkgs "usbguard" {
44 If you do not need the Qt GUI, use `pkgs.usbguard-nox` to save disk space.
49 type = types.nullOr types.path;
50 default = "/var/lib/usbguard/rules.conf";
51 example = "/run/secrets/usbguard-rules";
53 This tells the USBGuard daemon which file to load as policy rule set.
55 The file can be changed manually or via the IPC interface assuming it has the right file permissions.
57 For more details see {manpage}`usbguard-rules.conf(5)`.
62 type = types.nullOr types.lines;
65 allow with-interface equals { 08:*:* }
68 The USBGuard daemon will load this as the policy rule set.
69 As these rules are NixOS managed they are immutable and can't
70 be changed by the IPC interface.
72 If you do not set this option, the USBGuard daemon will load
73 it's policy rule set from the option configured in `services.usbguard.ruleFile`.
75 Running `usbguard generate-policy` as root will
76 generate a config for your currently plugged in devices.
78 For more details see {manpage}`usbguard-rules.conf(5)`.
82 implicitPolicyTarget = mkOption {
83 type = types.enum [ "allow" "block" "reject" ];
86 How to treat USB devices that don't match any rule in the policy.
87 Target should be one of allow, block or reject (logically remove the
88 device node from the system).
92 presentDevicePolicy = mkOption {
94 default = "apply-policy";
96 How to treat USB devices that are already connected when the daemon
97 starts. Policy should be one of allow, block, reject, keep (keep
98 whatever state the device is currently in) or apply-policy (evaluate
99 the rule set for every present device).
103 presentControllerPolicy = mkOption {
107 How to treat USB controller devices that are already connected when
108 the daemon starts. One of allow, block, reject, keep or apply-policy.
112 insertedDevicePolicy = mkOption {
113 type = types.enum [ "block" "reject" "apply-policy" ];
114 default = "apply-policy";
116 How to treat USB devices that are already connected after the daemon
117 starts. One of block, reject, apply-policy.
121 restoreControllerDeviceState = mkOption {
125 The USBGuard daemon modifies some attributes of controller
126 devices like the default authorization state of new child device
127 instances. Using this setting, you can control whether the daemon
128 will try to restore the attribute values to the state before
129 modification on shutdown.
133 IPCAllowedUsers = mkOption {
134 type = types.listOf types.str;
135 default = [ "root" ];
136 example = [ "root" "yourusername" ];
138 A list of usernames that the daemon will accept IPC connections from.
142 IPCAllowedGroups = mkOption {
143 type = types.listOf types.str;
145 example = [ "wheel" ];
147 A list of groupnames that the daemon will accept IPC connections
152 deviceRulesWithPort = mkOption {
156 Generate device specific rules including the "via-port" attribute.
160 dbus.enable = mkEnableOption "USBGuard dbus daemon";
165 ###### implementation
167 config = mkIf cfg.enable {
169 environment.systemPackages = [ cfg.package ];
173 description = "USBGuard daemon";
175 wantedBy = [ "basic.target" ];
176 wants = [ "systemd-udevd.service" ];
178 # make sure an empty rule file exists
179 preStart = ''[ -f "${ruleFile}" ] || touch ${ruleFile}'';
183 ExecStart = "${cfg.package}/bin/usbguard-daemon -P -k -c ${daemonConfFile}";
184 Restart = "on-failure";
188 "usbguard/IPCAccessControl.d"
191 AmbientCapabilities = "";
192 CapabilityBoundingSet = "CAP_CHOWN CAP_FOWNER";
193 DeviceAllow = "/dev/null rw";
194 DevicePolicy = "strict";
195 IPAddressDeny = "any";
196 LockPersonality = true;
197 MemoryDenyWriteExecute = true;
198 NoNewPrivileges = true;
199 PrivateDevices = true;
201 ProtectControlGroups = true;
203 ProtectKernelModules = true;
204 ProtectSystem = true;
205 ReadOnlyPaths = "-/";
206 ReadWritePaths = "-/dev/shm -/tmp";
207 RestrictAddressFamilies = [ "AF_UNIX" "AF_NETLINK" ];
208 RestrictNamespaces = true;
209 RestrictRealtime = true;
210 SystemCallArchitectures = "native";
211 SystemCallFilter = "@system-service";
216 usbguard-dbus = mkIf cfg.dbus.enable {
217 description = "USBGuard D-Bus Service";
219 wantedBy = [ "multi-user.target" ];
220 requires = [ "usbguard.service" ];
224 BusName = "org.usbguard1";
225 ExecStart = "${cfg.package}/bin/usbguard-dbus --system";
226 Restart = "on-failure";
229 aliases = [ "dbus-org.usbguard.service" ];
233 security.polkit.extraConfig =
235 groupCheck = (lib.concatStrings (map
236 (g: "subject.isInGroup(\"${g}\") || ")
237 cfg.IPCAllowedGroups))
240 optionalString cfg.dbus.enable ''
241 polkit.addRule(function(action, subject) {
242 if ((action.id == "org.usbguard.Policy1.listRules" ||
243 action.id == "org.usbguard.Policy1.appendRule" ||
244 action.id == "org.usbguard.Policy1.removeRule" ||
245 action.id == "org.usbguard.Devices1.applyDevicePolicy" ||
246 action.id == "org.usbguard.Devices1.listDevices" ||
247 action.id == "org.usbguard1.getParameter" ||
248 action.id == "org.usbguard1.setParameter") &&
249 subject.active == true && subject.local == true &&
251 return polkit.Result.YES;
257 (mkRemovedOptionModule [ "services" "usbguard" "IPCAccessControlFiles" ] "The usbguard module now hardcodes IPCAccessControlFiles to /var/lib/usbguard/IPCAccessControl.d.")
258 (mkRemovedOptionModule [ "services" "usbguard" "auditFilePath" ] "Removed usbguard module audit log files. Audit logs can be found in the systemd journal.")
259 (mkRenamedOptionModule [ "services" "usbguard" "implictPolicyTarget" ] [ "services" "usbguard" "implicitPolicyTarget" ])