1 Mod_apparmor
Steve Beattie edited this page 2017-11-07 12:47:15 -08:00

DRAFT

Overview

If a portion of a confined program needs different access permissions than other portions, the program can “change hats” via AppArmor's change_hat() mechanism to a sub-profile, or hat. The mod_apparmor Apache module uses change_hat() to offer more fine-grained confinement of dynamic elements within Apache, such as individual php and perl scripts, while still allowing the performance benefits of using mod_php and mod_perl.

To use mod_apparmor with Apache, ensure you have a functioning AppArmor using 'aa-status' and that mod_apparmor is loaded into Apache (using tools such as a2enmod and yast or manual editing of the Apache configuration files), then restart Apache.

URI Requests

Once mod_apparmor is loaded within Apache, all requests to Apache will cause mod_apparmor to attempt to change into a hat named by the URI that is defined in /etc/apparmor.d/. For example:

 $ cat /etc/apparmor.d/usr.lib.cgi-bin.some.cgi
 #include <tunables/global>
 /usr/lib/cgi-bin/some.cgi {
   ...
 }

If no such hat is found, it will attempt to use the DEFAULT_URI hat, if it exists. If this hat does not exist, mod_apparmor will fall back to using the global Apache profile. Most static web pages can simply make use of the DEFAULT_URI hat.

Additionally, to allow even more control, before any requests come in to Apache, mod_apparmor will attempt to change hat into the HANDLING_UNTRUSTED_INPUT hat while Apache is doing the initial parsing of a given http request, before the request is given to a specific handler (like mod_php) for processing. This hat can be used to provide an even stricter confinement while processing the untrusted input. Eg:

 $ cat /etc/apparmor.d/usr.sbin.apache2
 #include <tunables/global>
 /usr/sbin/apache2 {
   #
   # Global Apache policy
   #

   #include <abstractions/base>
   #include <abstractions/nameservice>

   capability kill,
   capability net_bind_service,
   capability setgid,
   capability setuid,
   capability sys_tty_config,

   /      r,
   /**/   r,
   /var/www/** r,

   #
   # Separate hat policies
   #
   ^DEFAULT_URI {
     ...
     /      r,
     /**/   r,
     /var/www/** r,
   }

   ^HANDLING_UNTRUSTED_INPUT {
     ...
     /      r,
     /**/   r,
   }

   ^foo {
     ...
     /usr/lib/cgi-bin/foo.gci ixr,
   }

   ^bar {
     ...
     /var/lib/bar/bar.py{,c} ixr,
   }
 }

Because defining hats for every URI/URL often becomes tedious, mod_apparmor provides the AAHatName and AADefaultHatName Apache configuration options.

AAHatName

AAHatName allows you to specify a hat to be used for a given Apache <Directory>, <DirectoryMatch>, <Location> or <LocationMatch> directive (see the Apache documentation for more details). Note that mod_apparmor behavior can become confused if <Directory*> and <Location*> directives are intermingled and it is recommended to use one type of directive. If the hat specified by AAHatName does not exist in the Apache profile, then it falls back to the behavior described above.

AADefaultHatName

AADefaultHatName allows you to specify a default hat to be used for virtual hosts and other Apache server directives, so that you can have different defaults for different virtual hosts. This can be overridden by the AAHatName directive and is checked for only if there isn't a matching AAHatName or hat named by the URI. If the AADefaultHatName hat does not exist, it falls back to the DEFAULT_URI hat if it exists (as described above).

Using mod_apparmor

Due to the flexibility of mod_apparmor, it might be unclear what mod_apparmor is doing behind the scenes. Put simply, on each URI request, mod_apparmor will:

  • change_hat() into ^HANDLING_UNTRUSTED_INPUT (if it exists) when performing the initial parsing of the request
  • after performing the initial parsing of the request mod_apparmor will:
    1. try to change_hat() into a matching AAHatName hat if it exists and applies, otherwise
    2. try to change_hat() into the URI itself, otherwise
    3. try to change_hat() into an AADefaultHatName hat if it has been defined for the server/vhost, otherwise
    4. try to change_hat() into the DEFAULT_URI hat, if it exists, otherwise
    5. fallback to the global Apache policy

Troublshooting

TODO: debugging options for seeing what AppArmor and Apache are doing

Examples

See 'Using mod_apparmor with Apache to confine web applications' for an example of how to use AppArmor to confine web applications with a trusted Apache daemon.

Caveats

mod_apparmor() currently only supports apache2, and has only been tested with the prefork MPM configuration. Threaded configurations of Apache may not work correctly. Additionally, due to how change_hat() is implemented, if there is a bug it is theoretically possible for a confined subprofile to break out of subprofile confinement (but still be confined by the global Apache profile).