diff --git a/nixos/modules/security/apparmor.nix b/nixos/modules/security/apparmor.nix index a4b3807e4e0f..87a2c2c81feb 100644 --- a/nixos/modules/security/apparmor.nix +++ b/nixos/modules/security/apparmor.nix @@ -3,15 +3,11 @@ with lib; let - inherit (builtins) attrNames head map match readFile; + inherit (builtins) attrNames map match; inherit (lib) types; inherit (config.environment) etc; cfg = config.security.apparmor; - mkDisableOption = name: mkEnableOption name // { - default = true; - example = false; - }; - enabledPolicies = filterAttrs (n: p: p.enable) cfg.policies; + enabledPolicies = filterAttrs (n: p: p.state != "disable") cfg.policies; in { @@ -45,15 +41,30 @@ in description = '' AppArmor policies. ''; - type = types.attrsOf (types.submodule ({ name, config, ... }: { + type = types.attrsOf (types.submodule ({ name, config, options, ... }: { options = { - enable = mkDisableOption "loading of the profile into the kernel"; - enforce = mkDisableOption "enforcing of the policy or only complain in the logs"; + state = mkOption { + description = + "The state of the profile as applied to the system by nix"; + type = types.enum [ "disable" "complain" "enforce" ]; + # should enforce really be the default? + # the docs state that this should only be used once one is REALLY sure nothing's gonna break + default = "enforce"; + }; + profile = mkOption { - description = "The policy of the profile."; + description = "The policy of the profile. Incompatible with path."; type = types.lines; - apply = pkgs.writeText name; }; + + path = mkOption { + type = types.nullOr types.path; + default = null; + description = "A path of a profile to include. Incompatible with profile."; + apply = p: assert (assertMsg ((p != null && !options.profile.isDefined) || (p == null && options.profile.isDefined)) + "`security.apparmor.policies.\"${name}\"` must define exactly one of either path or profile."); + (if (p != null) then p else (pkgs.writeText name config.profile)); + }; }; })); default = {}; @@ -108,7 +119,7 @@ in environment.etc."apparmor.d".source = pkgs.linkFarm "apparmor.d" ( # It's important to put only enabledPolicies here and not all cfg.policies # because aa-remove-unknown reads profiles from all /etc/apparmor.d/* - mapAttrsToList (name: p: { inherit name; path = p.profile; }) enabledPolicies ++ + mapAttrsToList (name: p: { inherit name; path = p.path; }) enabledPolicies ++ mapAttrsToList (name: path: { inherit name path; }) cfg.includes ); environment.etc."apparmor/parser.conf".text = '' @@ -187,7 +198,7 @@ in xargs --verbose --no-run-if-empty --delimiter='\n' \ kill ''; - commonOpts = p: "--verbose --show-cache ${optionalString (!p.enforce) "--complain "}${p.profile}"; + commonOpts = p: "--verbose --show-cache ${optionalString (p.state == "complain") "--complain "}${p.path}"; in { Type = "oneshot"; RemainAfterExit = "yes";