1 { config, lib, pkgs, ... }:
5 cfg = config.services.usbguard;
8 policy = (types.enum [ "allow" "block" "reject" "keep" "apply-policy" ]);
10 defaultRuleFile = "/var/lib/usbguard/rules.conf";
12 # decide what file to use for rules
13 ruleFile = if cfg.rules != null then pkgs.writeText "usbguard-rules" cfg.rules else defaultRuleFile;
16 # generated by nixos/modules/services/security/usbguard.nix
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
33 daemonConfFile = pkgs.writeText "usbguard-daemon-conf" daemonConf;
42 enable = mkEnableOption (lib.mdDoc "USBGuard daemon");
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.
55 type = types.nullOr types.lines;
58 allow with-interface equals { 08:*:* }
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.
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.
69 Running `usbguard generate-policy` as root will
70 generate a config for your currently plugged in devices.
72 For more details see {manpage}`usbguard-rules.conf(5)`.
76 implictPolicyTarget = mkOption {
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).
86 presentDevicePolicy = mkOption {
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).
97 presentControllerPolicy = mkOption {
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.
106 insertedDevicePolicy = mkOption {
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.
115 restoreControllerDeviceState = mkOption {
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 controll whether the daemon
122 will try to restore the attribute values to the state before
123 modificaton on shutdown.
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.
136 IPCAllowedGroups = mkOption {
137 type = types.listOf types.str;
139 example = [ "wheel" ];
140 description = lib.mdDoc ''
141 A list of groupnames that the daemon will accept IPC connections
146 deviceRulesWithPort = mkOption {
149 description = lib.mdDoc ''
150 Generate device specific rules including the "via-port" attribute.
157 ###### implementation
159 config = mkIf cfg.enable {
161 environment.systemPackages = [ cfg.package ];
163 systemd.services.usbguard = {
164 description = "USBGuard daemon";
166 wantedBy = [ "basic.target" ];
167 wants = [ "systemd-udevd.service" ];
169 # make sure an empty rule file exists
170 preStart = ''[ -f "${ruleFile}" ] || touch ${ruleFile}'';
174 ExecStart = "${cfg.package}/bin/usbguard-daemon -P -k -c ${daemonConfFile}";
175 Restart = "on-failure";
179 "usbguard/IPCAccessControl.d"
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;
192 ProtectControlGroups = 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";
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.")