diff options
Diffstat (limited to 'nixos/modules/services/security/usbguard.nix')
-rw-r--r-- | nixos/modules/services/security/usbguard.nix | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/nixos/modules/services/security/usbguard.nix b/nixos/modules/services/security/usbguard.nix new file mode 100644 index 00000000000..201b37f17ba --- /dev/null +++ b/nixos/modules/services/security/usbguard.nix @@ -0,0 +1,214 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.services.usbguard; + + # valid policy options + policy = (types.enum [ "allow" "block" "reject" "keep" "apply-policy" ]); + + defaultRuleFile = "/var/lib/usbguard/rules.conf"; + + # decide what file to use for rules + ruleFile = if cfg.rules != null then pkgs.writeText "usbguard-rules" cfg.rules else defaultRuleFile; + + daemonConf = '' + # generated by nixos/modules/services/security/usbguard.nix + RuleFile=${ruleFile} + ImplicitPolicyTarget=${cfg.implictPolicyTarget} + PresentDevicePolicy=${cfg.presentDevicePolicy} + PresentControllerPolicy=${cfg.presentControllerPolicy} + InsertedDevicePolicy=${cfg.insertedDevicePolicy} + RestoreControllerDeviceState=${boolToString cfg.restoreControllerDeviceState} + # this does not seem useful for endusers to change + DeviceManagerBackend=uevent + IPCAllowedUsers=${concatStringsSep " " cfg.IPCAllowedUsers} + IPCAllowedGroups=${concatStringsSep " " cfg.IPCAllowedGroups} + IPCAccessControlFiles=/var/lib/usbguard/IPCAccessControl.d/ + DeviceRulesWithPort=${boolToString cfg.deviceRulesWithPort} + # HACK: that way audit logs still land in the journal + AuditFilePath=/dev/null + ''; + + daemonConfFile = pkgs.writeText "usbguard-daemon-conf" daemonConf; + +in +{ + + ###### interface + + options = { + services.usbguard = { + enable = mkEnableOption "USBGuard daemon"; + + package = mkOption { + type = types.package; + default = pkgs.usbguard; + defaultText = literalExpression "pkgs.usbguard"; + description = '' + The usbguard package to use. If you do not need the Qt GUI, use + <literal>pkgs.usbguard-nox</literal> to save disk space. + ''; + }; + + rules = mkOption { + type = types.nullOr types.lines; + default = null; + example = '' + allow with-interface equals { 08:*:* } + ''; + description = '' + The USBGuard daemon will load this as the policy rule set. + As these rules are NixOS managed they are immutable and can't + be changed by the IPC interface. + + If you do not set this option, the USBGuard daemon will load + it's policy rule set from <literal>${defaultRuleFile}</literal>. + This file can be changed manually or via the IPC interface. + + Running <literal>usbguard generate-policy</literal> as root will + generate a config for your currently plugged in devices. + + For more details see <citerefentry> + <refentrytitle>usbguard-rules.conf</refentrytitle> + <manvolnum>5</manvolnum></citerefentry>. + ''; + }; + + implictPolicyTarget = mkOption { + type = policy; + default = "block"; + description = '' + How to treat USB devices that don't match any rule in the policy. + Target should be one of allow, block or reject (logically remove the + device node from the system). + ''; + }; + + presentDevicePolicy = mkOption { + type = policy; + default = "apply-policy"; + description = '' + How to treat USB devices that are already connected when the daemon + starts. Policy should be one of allow, block, reject, keep (keep + whatever state the device is currently in) or apply-policy (evaluate + the rule set for every present device). + ''; + }; + + presentControllerPolicy = mkOption { + type = policy; + default = "keep"; + description = '' + How to treat USB controller devices that are already connected when + the daemon starts. One of allow, block, reject, keep or apply-policy. + ''; + }; + + insertedDevicePolicy = mkOption { + type = policy; + default = "apply-policy"; + description = '' + How to treat USB devices that are already connected after the daemon + starts. One of block, reject, apply-policy. + ''; + }; + + restoreControllerDeviceState = mkOption { + type = types.bool; + default = false; + description = '' + The USBGuard daemon modifies some attributes of controller + devices like the default authorization state of new child device + instances. Using this setting, you can controll whether the daemon + will try to restore the attribute values to the state before + modificaton on shutdown. + ''; + }; + + IPCAllowedUsers = mkOption { + type = types.listOf types.str; + default = [ "root" ]; + example = [ "root" "yourusername" ]; + description = '' + A list of usernames that the daemon will accept IPC connections from. + ''; + }; + + IPCAllowedGroups = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "wheel" ]; + description = '' + A list of groupnames that the daemon will accept IPC connections + from. + ''; + }; + + deviceRulesWithPort = mkOption { + type = types.bool; + default = false; + description = '' + Generate device specific rules including the "via-port" attribute. + ''; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + + environment.systemPackages = [ cfg.package ]; + + systemd.services.usbguard = { + description = "USBGuard daemon"; + + wantedBy = [ "basic.target" ]; + wants = [ "systemd-udevd.service" ]; + + # make sure an empty rule file exists + preStart = ''[ -f "${ruleFile}" ] || touch ${ruleFile}''; + + serviceConfig = { + Type = "simple"; + ExecStart = "${cfg.package}/bin/usbguard-daemon -P -k -c ${daemonConfFile}"; + Restart = "on-failure"; + + StateDirectory = [ + "usbguard" + "usbguard/IPCAccessControl.d" + ]; + + AmbientCapabilities = ""; + CapabilityBoundingSet = "CAP_CHOWN CAP_FOWNER"; + DeviceAllow = "/dev/null rw"; + DevicePolicy = "strict"; + IPAddressDeny = "any"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectKernelModules = true; + ProtectSystem = true; + ReadOnlyPaths = "-/"; + ReadWritePaths = "-/dev/shm -/tmp"; + RestrictAddressFamilies = [ "AF_UNIX" "AF_NETLINK" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = "@system-service"; + UMask = "0077"; + }; + }; + }; + imports = [ + (mkRemovedOptionModule [ "services" "usbguard" "ruleFile" ] "The usbguard module now uses ${defaultRuleFile} as ruleFile. Alternatively, use services.usbguard.rules to configure rules.") + (mkRemovedOptionModule [ "services" "usbguard" "IPCAccessControlFiles" ] "The usbguard module now hardcodes IPCAccessControlFiles to /var/lib/usbguard/IPCAccessControl.d.") + (mkRemovedOptionModule [ "services" "usbguard" "auditFilePath" ] "Removed usbguard module audit log files. Audit logs can be found in the systemd journal.") + ]; +} |