at master 4.3 kB view raw
1{ pkgs, lib, ... }: 2let 3 helloProfileContents = '' 4 abi <abi/4.0>, 5 include <tunables/global> 6 profile hello ${lib.getExe pkgs.hello} { 7 include <abstractions/base> 8 } 9 ''; 10in 11{ 12 name = "apparmor"; 13 meta.maintainers = with lib.maintainers; [ 14 julm 15 grimmauld 16 ]; 17 18 nodes.machine = 19 { 20 lib, 21 ... 22 }: 23 { 24 security.apparmor = { 25 enable = lib.mkDefault true; 26 27 policies.hello = { 28 # test profile enforce and content definition 29 state = "enforce"; 30 profile = helloProfileContents; 31 }; 32 33 policies.sl = { 34 # test profile complain and path definition 35 state = "complain"; 36 path = ./sl_profile; 37 }; 38 39 policies.hexdump = { 40 # test profile complain and path definition 41 state = "enforce"; 42 profile = '' 43 abi <abi/4.0>, 44 include <tunables/global> 45 profile hexdump /nix/store/*/bin/hexdump { 46 include <abstractions/base> 47 deny /tmp/** r, 48 } 49 ''; 50 }; 51 52 includes."abstractions/base" = '' 53 /nix/store/*/bin/** mr, 54 /nix/store/*/lib/** mr, 55 /nix/store/** r, 56 ''; 57 }; 58 }; 59 60 testScript = 61 let 62 inherit (lib) getExe getExe'; 63 in 64 '' 65 machine.wait_for_unit("multi-user.target") 66 67 with subtest("AppArmor profiles are loaded"): 68 machine.succeed("systemctl status apparmor.service") 69 70 # AppArmor securityfs 71 with subtest("AppArmor securityfs is mounted"): 72 machine.succeed("mountpoint -q /sys/kernel/security") 73 machine.succeed("cat /sys/kernel/security/apparmor/profiles") 74 75 # Test apparmorRulesFromClosure by: 76 # 1. Prepending a string of the relevant packages' name and version on each line. 77 # 2. Sorting according to those strings. 78 # 3. Removing those prepended strings. 79 # 4. Using `diff` against the expected output. 80 with subtest("apparmorRulesFromClosure"): 81 machine.succeed( 82 "${getExe' pkgs.diffutils "diff"} -u ${ 83 pkgs.writeText "expected.rules" (import ./makeExpectedPolicies.nix { inherit pkgs; }) 84 } ${ 85 pkgs.runCommand "actual.rules" { preferLocalBuild = true; } '' 86 ${getExe pkgs.gnused} -e 's:^[^ ]* ${builtins.storeDir}/[^,/-]*-\([^/,]*\):\1 \0:' ${ 87 pkgs.apparmorRulesFromClosure { 88 name = "ping"; 89 additionalRules = [ "x $path/foo/**" ]; 90 } [ pkgs.libcap ] 91 } | 92 ${getExe' pkgs.coreutils "sort"} -n -k1 | 93 ${getExe pkgs.gnused} -e 's:^[^ ]* ::' >$out 94 '' 95 }" 96 ) 97 98 # Test apparmor profile states by using `diff` against `aa-status` 99 with subtest("apparmorProfileStates"): 100 machine.succeed("${getExe' pkgs.diffutils "diff"} -u \ 101 <(${getExe' pkgs.apparmor-bin-utils "aa-status"} --json | ${getExe pkgs.jq} --sort-keys . ) \ 102 <(${getExe pkgs.jq} --sort-keys . ${ 103 pkgs.writers.writeJSON "expectedStates.json" { 104 version = "2"; 105 processes = { }; 106 profiles = { 107 hexdump = "enforce"; 108 hello = "enforce"; 109 sl = "complain"; 110 }; 111 } 112 })") 113 114 # Test apparmor profile files in /etc/apparmor.d/<name> to be either a correct symlink (sl) or have the right file contents (hello) 115 with subtest("apparmorProfileTargets"): 116 machine.succeed("${getExe' pkgs.diffutils "diff"} -u <(${getExe pkgs.file} /etc/static/apparmor.d/sl) ${pkgs.writeText "expected.link" '' 117 /etc/static/apparmor.d/sl: symbolic link to ${./sl_profile} 118 ''}") 119 machine.succeed("${getExe' pkgs.diffutils "diff"} -u /etc/static/apparmor.d/hello ${pkgs.writeText "expected.content" helloProfileContents}") 120 121 122 with subtest("apparmorProfileEnforce"): 123 machine.succeed("${getExe pkgs.hello} 1> /tmp/test-file") 124 machine.fail("${lib.getExe' pkgs.util-linux "hexdump"} /tmp/test-file") # no access to /tmp/test-file granted by apparmor 125 ''; 126}