]> Git — Sourcephile - sourcephile-nix.git/blob - nixos/modules/security/apparmor.nix
apparmor: fix path
[sourcephile-nix.git] / nixos / modules / security / apparmor.nix
1 { config, lib, pkgs, ... }:
2
3 let
4 inherit (builtins) attrNames head match readFile;
5 inherit (lib) types;
6 inherit (config.environment) etc;
7 cfg = config.security.apparmor;
8 aa-teardown = pkgs.writeShellScriptBin "aa-teardown" ''
9 SECURITYFS=/sys/kernel/security
10 SFS_MOUNTPOINT="$SECURITYFS/apparmor"
11 ${pkgs.gnused}/bin/sed -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" | \
12 LC_COLLATE=C ${pkgs.coreutils}/bin/sort | ${pkgs.gnugrep}/bin/grep -v // | {
13 while read -r profile ; do
14 printf "%s" "$profile" > "$SFS_MOUNTPOINT/.remove"
15 rc=$?
16 if [ "$rc" -ne 0 ] ; then
17 retval=$rc
18 fi
19 done
20 exit "''${retval:-0}"
21 }
22 '';
23 in
24
25 {
26 options = {
27 security.apparmor = {
28 enable = lib.mkEnableOption "Whether to enable the AppArmor Mandatory Access Control system.";
29 enableCache = lib.mkOption {
30 type = types.bool;
31 default = true;
32 example = false;
33 description = ''
34 Whether to enable caching of AppArmor profiles
35 in <literal>/var/cache/apparmor/</literal>.
36 '';
37 };
38 profiles = lib.mkOption {
39 type = types.attrsOf types.lines;
40 default = {};
41 description = ''
42 Available AppArmor profiles.
43 '';
44 apply = lib.mapAttrs (name: text: pkgs.writeText "${name}" text);
45 };
46 enforceProfiles = lib.mkOption {
47 type = (types.listOf (types.enum (attrNames cfg.profiles))) // {
48 description = "list of profiles";
49 };
50 default = [];
51 description = "List of AppArmor profiles to be enforced.";
52 };
53 complainProfiles = lib.mkOption {
54 type = (types.listOf (types.enum (attrNames cfg.profiles))) // {
55 description = "list of profiles";
56 };
57 default = [];
58 description = "List of AppArmor profiles to be complained.";
59 };
60 includes = lib.mkOption {
61 type = types.listOf types.path;
62 default = [];
63 description = ''
64 List of paths to be added to AppArmor's searched paths
65 when resolving absolute #include directives.
66 '';
67 # Prepends /etc/apparmor.d so that apparmor.profiles
68 # are included in priority over apparmor.includes.
69 apply = is: ["/etc/apparmor.d"] ++ is;
70 };
71 };
72 };
73
74 config = lib.mkIf cfg.enable {
75 environment.systemPackages = [ pkgs.apparmor-utils aa-teardown ];
76 environment.etc."apparmor.d".source = pkgs.linkFarm "apparmor.d" (
77 lib.mapAttrsToList (name: path: {inherit name path;}) cfg.profiles
78 );
79 environment.etc."apparmor/parser.conf".text = ''
80 ${if cfg.enableCache then "write-cache" else "skip-cache"}
81 cache-loc /var/cache/apparmor
82 '' + lib.concatMapStringsSep "\n" (p: "Include ${p}") cfg.includes;
83 environment.etc."apparmor/logprof.conf".text = ''
84 [settings]
85 profiledir = /etc/apparmor.d /etc/subdomain.d
86 inactive_profiledir = ${pkgs.apparmor-profiles}/share/apparmor/extra-profiles
87 logfiles = /var/log/audit/audit.log /var/log/syslog /var/log/messages
88
89 parser = ${pkgs.apparmor-parser}/bin/apparmor_parser ${pkgs.apparmor-parser}/bin/subdomain_parser
90 ldd = ${pkgs.glibc.bin}/bin/ldd
91 logger = ${pkgs.utillinux}/bin/logger
92
93 # customize how file ownership permissions are presented
94 # 0 - off
95 # 1 - default of what ever mode the log reported
96 # 2 - force the new permissions to be user
97 # 3 - force all perms on the rule to be user
98 default_owner_prompt = 1
99
100 # custom directory locations to look for #includes
101 #
102 # each name should be a valid directory containing possible #include
103 # candidate files under the profile dir which by default is /etc/apparmor.d.
104 #
105 # So an entry of my-includes will allow /etc/apparmor.d/my-includes to
106 # be used by the yast UI and profiling tools as a source of #include
107 # files.
108 custom_includes =
109
110 [qualifiers]
111 ${pkgs.runtimeShell} = icnu
112 '' + head (match "^.*\\[qualifiers](.*)" # Drop the original [settings] section.
113 (readFile "${pkgs.apparmor-utils}/etc/apparmor/logprof.conf"));
114 security.apparmor.profiles = {
115 "abstractions/tunables/alias" = ''
116 alias /bin -> /run/current-system/sw/bin,
117 #alias /etc -> /run/current-system/etc,
118 alias /lib/modules -> /run/current-system/kernel/lib/modules,
119 alias /sbin -> /run/current-system/sw/sbin,
120 alias /usr -> /run/current-system/sw,
121 '';
122 "abstractions/base" = ''
123 #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/base
124 ${etc."hosts".source} r,
125 /etc/ld-nix.so.preload r,
126 ${etc."ld-nix.so.preload".source} r,
127 ${lib.concatMapStrings (p: lib.optionalString (p != "") (p+" mr,\n"))
128 (lib.splitString "\n" etc."ld-nix.so.preload".text)
129 # TODO: export the content of ld-nix.so.preload as a list or attrset
130 # and make services.config.malloc use it.
131 }
132 ${pkgs.tzdata}/share/zoneinfo/** r,
133 '';
134 "abstractions/consoles" = ''
135 #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/consoles
136 '';
137 "abstractions/ldapclient" = ''
138 #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/ldapclient
139 '';
140 "abstractions/kerberosclient" = ''
141 #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/kerberosclient
142 '';
143 "abstractions/likewise" = ''
144 #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/likewise
145 '';
146 "abstractions/mdns" = ''
147 #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/mdns
148 '';
149 "abstractions/nameservice" = ''
150 #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nameservice
151 '';
152 "abstractions/nis" = ''
153 #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nis
154 '';
155 "abstractions/ssl_certs" = ''
156 #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/ssl_certs
157 ${etc."ssl/certs/ca-certificates.crt".source} r,
158 ${etc."ssl/certs/ca-bundle.crt".source} r,
159 '';
160 "abstractions/winbind" = ''
161 #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/winbind
162 '';
163 };
164 security.apparmor.includes = [ (pkgs.apparmor-profiles+"/etc/apparmor.d/") ];
165
166 boot.kernelParams = [ "apparmor=1" "security=apparmor" ];
167
168 systemd.services.apparmor = {
169 after = [
170 "local-fs.target"
171 "systemd-journald-audit.socket"
172 ];
173 before = [ "sysinit.target" ];
174 wantedBy = [ "multi-user.target" ];
175 restartTriggers = [
176 etc."apparmor/parser.conf".source
177 etc."apparmor.d".source
178 ] ++ cfg.includes;
179 unitConfig = {
180 Description="Load AppArmor profiles";
181 DefaultDependencies = "no";
182 ConditionSecurity = "apparmor";
183 };
184 environment.LANG="C"; # Avoid searchs in /usr/share/locale/
185 # Restart because reloading would not remove confinement from removed profiles.
186 # However, restarting apparmor.service will restart services
187 # which Requires= apparmor.service.
188 restartIfChanged = true;
189 serviceConfig =
190 let commonOpts = p: ''--verbose --show-cache ${cfg.profiles."${p}"}'';
191 in {
192 Type = "oneshot";
193 RemainAfterExit = "yes";
194 ExecStartPre = "${aa-teardown}/bin/aa-teardown";
195 ExecStart =
196 map (p: ''${pkgs.strace}/bin/strace -f -e file ${pkgs.apparmor-parser}/bin/apparmor_parser --add ${commonOpts p}'') cfg.enforceProfiles ++
197 map (p: ''${pkgs.strace}/bin/strace -f -e file ${pkgs.apparmor-parser}/bin/apparmor_parser --add --complain ${commonOpts p}'') cfg.complainProfiles;
198 ExecReload = # WARNING: reloading does NOT remove AppArmor confinement from running processes
199 # (as we would not be able to re-confine them without restarting them).
200 # However, processes confined with profiles just removed
201 # from cfg.enforceProfiles or cfg.complainProfiles,
202 # will stay confined with those removed profiles.
203 map (p: ''${pkgs.apparmor-parser}/bin/apparmor_parser --replace ${commonOpts p}'') cfg.enforceProfiles ++
204 map (p: ''${pkgs.apparmor-parser}/bin/apparmor_parser --replace --complain ${commonOpts p}'') cfg.complainProfiles;
205 ExecStop = "${aa-teardown}/bin/aa-teardown";
206 } // lib.optionalAttrs cfg.enableCache {
207 #WorkingDirectory = "/var/cache/apparmor";
208 CacheDirectory = [ "apparmor" ];
209 CacheDirectoryMode = "0700";
210 };
211 };
212 };
213
214 meta.maintainers = with lib.maintainers; [ julm ];
215 }