AppArmor vs SELinux

By Andrew Cozzetta –

AppArmor:

AppArmor is a Mandatory Access Control (MAC) Linux Security Module (LSM) giving administrators the ability to restrict the permissions of applications (Apache, MySQL, CUPS, etc) via application profiles. These restrictions can greatly help in the event an application becomes compromised by limiting the resources accessible to the application. AppArmor has been included in the mainline Linux kernel since 2.6.36 and has been supported by Canonical since 2009. It is the LSM of choice for current Ubuntu Desktop and Server installations. Many believe that AppArmor is easier to configure compared to its LSM competitor, SELinux (which we will be covering later on). Below are the topics we are going to cover for AppArmor:

  • Installation
  • Checking AppArmor Status
  • Dissecting Application Profile Configurations
  • Changing Profile Modes of Operation
  • Enabling and Disabling AppArmor
  • Enabling and Disabling Application Profiles
  • Creating/Editing Application Profiles
  • Summary

Installation

Note: For this tutorial we will be using Ubuntu Server 16.10 which already includes AppArmor

AppArmor comes installed and enabled by default on both Server and Desktop distributions of the popular Linux flavor Ubuntu. To use AppArmors full functionality you should install the following packages:

  • sudo apt-get install apparmor-profiles
  • sudo apt-get install apparmor-utils

Installing the apparmor-profiles package installs predefined profiles. Profiles can be installed automatically when installing applications (if the application supports it) or manually. Installing the apparmor-utils package installs the utilities necessary to change the AppArmor execution mode, find the status of a profile, and create new profiles.

Checking AppArmor Status

The running status of AppArmor can be checked using the following command:

  • sudo apparmor_status

Your output should look similar to this:


acozzetta@ubuntu-server:~$ sudo apparmor_status
apparmor module is loaded.
12 profiles are loaded.
12 profiles are in enforce mode.
   /sbin/dhclient
   /usr/bin/lxc-start
   /usr/lib/NetworkManager/nm-dhcp-client.action
   /usr/lib/NetworkManager/nm-dhcp-helper
   /usr/lib/connman/scripts/dhclient-script
   /usr/lib/snapd/snap-confine
   /usr/lib/snapd/snap-confine//mount-namespace-capture-helper
   /usr/sbin/tcpdump
   lxc-container-default
   lxc-container-default-cgns
   lxc-container-default-with-mounting
   lxc-container-default-with-nesting
0 profiles are in complain mode.
1 processes have profiles defined.
1 processes are in enforce mode.
   /sbin/dhclient (1430)
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.

From this output we can see that AppArmor is successfully loaded via the apparmor module is loaded line of output. We can also see that we have a total of 12 profiles loaded into AppArmor, all of them in enforce mode. Each of these application profiles are stored in /etc/apparmor.d as shown below:


acozzetta@ubuntu-server:/etc/apparmor.d$ pwd
/etc/apparmor.d
acozzetta@ubuntu-server:/etc/apparmor.d$ ls -l
total 60
drwxr-xr-x 5 root root  4096 Nov 24 12:45 abstractions
drwxr-xr-x 2 root root  4096 Nov 24 12:45 cache
drwxr-xr-x 2 root root  4096 Nov 24 12:29 disable
drwxr-xr-x 2 root root  4096 Sep  8 12:57 force-complain
drwxr-xr-x 2 root root  4096 Nov 24 12:45 local
drwxr-xr-x 2 root root  4096 Nov 24 12:45 lxc
-rw-r--r-- 1 root root   198 Oct  5 07:56 lxc-containers
-rw-r--r-- 1 root root  3310 Apr 12  2016 sbin.dhclient
drwxr-xr-x 5 root root  4096 Nov 24 12:45 tunables
-rw-r--r-- 1 root root   125 Oct  5 07:56 usr.bin.lxc-start
-rw-r--r-- 1 root root 11744 Oct  6 08:29 usr.lib.snapd.snap-confine
-rw-r--r-- 1 root root  1527 Jan  5  2016 usr.sbin.rsyslogd
-rw-r--r-- 1 root root  1455 Oct 11 12:44 usr.sbin.tcpdump

Later on we will go into creating new profiles and editing existing ones. What we will do next is install additional application profiles by running the following command (mentioned earlier):

  • sudo apt-get install apparmor-profiles

From the output below we are able to see that the number of newly installed application profiles is directly reflected in the /etc/apparmor.d directory.


acozzetta@ubuntu-server:~$ sudo apparmor_status
apparmor module is loaded.
52 profiles are loaded.
15 profiles are in enforce mode.
   /sbin/dhclient
   /usr/bin/lxc-start
   /usr/lib/NetworkManager/nm-dhcp-client.action
   /usr/lib/NetworkManager/nm-dhcp-helper
   /usr/lib/chromium-browser/chromium-browser//browser_java
   /usr/lib/chromium-browser/chromium-browser//browser_openjdk
   /usr/lib/chromium-browser/chromium-browser//sanitized_helper
   /usr/lib/connman/scripts/dhclient-script
   /usr/lib/snapd/snap-confine
   /usr/lib/snapd/snap-confine//mount-namespace-capture-helper
   /usr/sbin/tcpdump
   lxc-container-default
   lxc-container-default-cgns
   lxc-container-default-with-mounting
   lxc-container-default-with-nesting
37 profiles are in complain mode.
   /usr/lib/chromium-browser/chromium-browser
   /usr/lib/chromium-browser/chromium-browser//chromium_browser_sandbox
   /usr/lib/chromium-browser/chromium-browser//lsb_release
   /usr/lib/chromium-browser/chromium-browser//xdgsettings
   /usr/lib/dovecot/anvil
   /usr/lib/dovecot/auth
   /usr/lib/dovecot/config
   /usr/lib/dovecot/deliver
   /usr/lib/dovecot/dict
   /usr/lib/dovecot/dovecot-auth
   /usr/lib/dovecot/dovecot-lda
   /usr/lib/dovecot/dovecot-lda///usr/sbin/sendmail
   /usr/lib/dovecot/imap
   /usr/lib/dovecot/imap-login
   /usr/lib/dovecot/lmtp
   /usr/lib/dovecot/log
   /usr/lib/dovecot/managesieve
   /usr/lib/dovecot/managesieve-login
   /usr/lib/dovecot/pop3
   /usr/lib/dovecot/pop3-login
   /usr/lib/dovecot/ssl-params
   /usr/sbin/avahi-daemon
   /usr/sbin/dnsmasq
   /usr/sbin/dnsmasq//libvirt_leaseshelper
   /usr/sbin/dovecot
   /usr/sbin/identd
   /usr/sbin/mdnsd
   /usr/sbin/nmbd
   /usr/sbin/nscd
   /usr/sbin/smbd
   /usr/sbin/smbldap-useradd
   /usr/sbin/smbldap-useradd///etc/init.d/nscd
   /usr/{sbin/traceroute,bin/traceroute.db}
   /{usr/,}bin/ping
   klogd
   syslog-ng
   syslogd
1 processes have profiles defined.
1 processes are in enforce mode.
   /sbin/dhclient (1430)
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.


acozzetta@ubuntu-server:/etc/apparmor.d$ pwd
/etc/apparmor.d
acozzetta@ubuntu-server:/etc/apparmor.d$ ls -l
total 196
drwxr-xr-x 5 root root  4096 Nov 24 12:45 abstractions
drwxr-xr-x 2 root root  4096 Nov 26 23:25 apache2.d
-rw-r--r-- 1 root root   802 Oct 11 21:47 bin.ping
drwxr-xr-x 2 root root  4096 Nov 26 23:25 cache
drwxr-xr-x 2 root root  4096 Nov 24 12:29 disable
drwxr-xr-x 2 root root  4096 Sep  8 12:57 force-complain
drwxr-xr-x 2 root root  4096 Nov 26 23:25 local
drwxr-xr-x 2 root root  4096 Nov 24 12:45 lxc
-rw-r--r-- 1 root root   198 Oct  5 07:56 lxc-containers
-rw-r--r-- 1 root root  3310 Apr 12  2016 sbin.dhclient
-rw-r--r-- 1 root root   999 Oct 11 21:47 sbin.klogd
-rw-r--r-- 1 root root  1307 Oct 11 21:47 sbin.syslogd
-rw-r--r-- 1 root root  1929 Oct 11 21:47 sbin.syslog-ng
drwxr-xr-x 5 root root  4096 Nov 24 12:45 tunables
-rw-r--r-- 1 root root  8243 Oct 11 21:47 usr.bin.chromium-browser
-rw-r--r-- 1 root root   125 Oct  5 07:56 usr.bin.lxc-start
-rw-r--r-- 1 root root   733 Oct 11 21:47 usr.lib.dovecot.anvil
-rw-r--r-- 1 root root  1204 Oct 11 21:47 usr.lib.dovecot.auth
-rw-r--r-- 1 root root   871 Oct 11 21:47 usr.lib.dovecot.config
-rw-r--r-- 1 root root  1153 Oct 11 21:47 usr.lib.dovecot.deliver
-rw-r--r-- 1 root root   887 Oct 11 21:47 usr.lib.dovecot.dict
-rw-r--r-- 1 root root  1056 Oct 11 21:47 usr.lib.dovecot.dovecot-auth
-rw-r--r-- 1 root root  2619 Oct 11 21:47 usr.lib.dovecot.dovecot-lda
-rw-r--r-- 1 root root  1003 Oct 11 21:47 usr.lib.dovecot.imap
-rw-r--r-- 1 root root  1008 Oct 11 21:47 usr.lib.dovecot.imap-login
-rw-r--r-- 1 root root  1006 Oct 11 21:47 usr.lib.dovecot.lmtp
-rw-r--r-- 1 root root   680 Oct 11 21:47 usr.lib.dovecot.log
-rw-r--r-- 1 root root   953 Oct 11 21:47 usr.lib.dovecot.managesieve
-rw-r--r-- 1 root root  1109 Oct 11 21:47 usr.lib.dovecot.managesieve-login
-rw-r--r-- 1 root root   900 Oct 11 21:47 usr.lib.dovecot.pop3
-rw-r--r-- 1 root root   967 Oct 11 21:47 usr.lib.dovecot.pop3-login
-rw-r--r-- 1 root root   790 Oct 11 21:47 usr.lib.dovecot.ssl-params
-rw-r--r-- 1 root root 11744 Oct  6 08:29 usr.lib.snapd.snap-confine
-rw-r--r-- 1 root root   916 Oct 11 21:47 usr.sbin.avahi-daemon
-rw-r--r-- 1 root root  3123 Oct 11 21:47 usr.sbin.dnsmasq
-rw-r--r-- 1 root root  2012 Oct 11 21:47 usr.sbin.dovecot
-rw-r--r-- 1 root root  1013 Oct 11 21:47 usr.sbin.identd
-rw-r--r-- 1 root root   964 Oct 11 21:47 usr.sbin.mdnsd
-rw-r--r-- 1 root root   761 Oct 11 21:47 usr.sbin.nmbd
-rw-r--r-- 1 root root  1255 Oct 11 21:47 usr.sbin.nscd
-rw-r--r-- 1 root root  1527 Jan  5  2016 usr.sbin.rsyslogd
-rw-r--r-- 1 root root  1413 Oct 11 21:47 usr.sbin.smbd
-rw-r--r-- 1 root root   920 Oct 11 21:47 usr.sbin.smbldap-useradd
-rw-r--r-- 1 root root  1455 Oct 11 12:44 usr.sbin.tcpdump
-rw-r--r-- 1 root root   842 Oct 11 21:47 usr.sbin.traceroute
acozzetta@ubuntu-server:/etc/apparmor.d$

You can see that there are a lot more entries, most of the new entries are in complain mode. It is important to note that just because there are additional profiles in the status list, it does not mean that the application they go with are installed on our system. For example, Dovecot (listed in the status profile list) is not installed on our system yet it is included in the command output. You may be wondering what the contents of these profiles look like, so lets take a look.

Dissecting Application Profile Configurations

For our configuration dissection we will be using the pre-existing bin.ping profile. The configuration for the bin.ping file in /etc/apparmor.d looks like this:

   
#include <tunables/global>
/{usr/,}bin/ping flags=(complain) {
  #include <abstractions/base>
  #include <abstractions/consoles>
  #include <abstractions/nameservice>

  capability net_raw,
  capability setuid,
  network inet raw,

  /{,usr/}bin/ping mixr,
  /etc/modules.conf r,

  # Site-specific additions and overrides. See local/README for details.
  #include <local/bin.ping>
}
   

Lets dissect some of these lines:

  • #include <tunables/global>: Include statements from other files. This allows statements pertaining to multiple applications to be placed in a common file
  • bin/ping flags=(complain): Path to the profiled program, also setting the mode to complain
  • capability net_raw,: Allows the application access to the CAP_NET_RAW Posix.1e capability
  • capability setuid,: Allows the application to change UIDs
  • network inet raw,: Allows the application to use a raw socket
  • bin/ping mixr,: Allows the application read and execute access to the file

Later on when we go into creating our own application profile we will revisit these configuration files.

Changing Profile Modes of Operation

As we have seen, applications configured for AppArmor run in either of the following two modes:

  • Enforce: The system enforces the defined rules and reports any violations of these rules in syslog and/or auditd
  • Complain: Rules are not enforced and only audited to syslog and/or auditd

To put a profile in Enforce mode run the following command (using the ping utility as an example):

  • sudo aa-enforce /etc/apparmor.d/bin.ping

Additionally you can use wildcards to change all profiles to enforcing mode using the following command:

  • sudo aa-enforce /etc/apparmor.d/*

To put a profile in Complain mode run the following command (using the ping utility as an example):

  • sudo aa-complain /etc/apparmor.d/bin.ping

Additionally you can use wildcards to change all profiles to complain mode using the following command:

  • sudo aa-complain /etc/apparmor.d/*

Enabling and Disabling AppArmor

Though it is not recommended to completely disable AppArmor, you have the ability to do so.

To disable AppArmor and unload the kernel module run the following commands:

  • sudo systemctl stop apparmor.service
  • sudo update-rc.d -f apparmor remove

To re-enable AppArmor run the following commands:

  • sudo systemctl start apparmor.service
  • sudo update-rc.d apparmor defaults

Enabling and Disabling Application Profiles

AppArmor also allows us to disable individual application profiles both permanently (the changes survive reboots) and temporarily (changes are reverted upon reboot). This feature is helpful when we need to troubleshoot an application restricted by AppArmor without bringing down all of AppArmor’s security measures. Below are examples of these:

Temporarily disabling a profile (using tcpdump which has a profile name of usr.sbin.tcpdump):

  • sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.tcpdump

Notice that we are using the apparmor_parser command which we haven’t seen before. This command lets us load and unload AppArmor profiles into the kernel.

Before running command:

   
acozzetta@ubuntu-server:~$ sudo apparmor_status
apparmor module is loaded.
52 profiles are loaded.
15 profiles are in enforce mode.
   /sbin/dhclient
   /usr/bin/lxc-start
   /usr/lib/NetworkManager/nm-dhcp-client.action
   /usr/lib/NetworkManager/nm-dhcp-helper
   /usr/lib/chromium-browser/chromium-browser//browser_java
   /usr/lib/chromium-browser/chromium-browser//browser_openjdk
   /usr/lib/chromium-browser/chromium-browser//sanitized_helper
   /usr/lib/connman/scripts/dhclient-script
   /usr/lib/snapd/snap-confine
   /usr/lib/snapd/snap-confine//mount-namespace-capture-helper
   /usr/sbin/tcpdump
   lxc-container-default
   lxc-container-default-cgns
   lxc-container-default-with-mounting
   lxc-container-default-with-nesting
   

After running command:

   
acozzetta@ubuntu-server:~$ sudo apparmor_status
apparmor module is loaded.
51 profiles are loaded.
14 profiles are in enforce mode.
   /sbin/dhclient
   /usr/bin/lxc-start
   /usr/lib/NetworkManager/nm-dhcp-client.action
   /usr/lib/NetworkManager/nm-dhcp-helper
   /usr/lib/chromium-browser/chromium-browser//browser_java
   /usr/lib/chromium-browser/chromium-browser//browser_openjdk
   /usr/lib/chromium-browser/chromium-browser//sanitized_helper
   /usr/lib/connman/scripts/dhclient-script
   /usr/lib/snapd/snap-confine
   /usr/lib/snapd/snap-confine//mount-namespace-capture-helper
   lxc-container-default
   lxc-container-default-cgns
   lxc-container-default-with-mounting
   lxc-container-default-with-nesting
   

As you can see, /usr/sbin/tcpdump is not longer in our status list.

Permanently disabling a profile (using tcpdump which has a profile name of usr.sbin.tcpdump):

  • sudo ln -s /etc/apparmor.d/usr.sbin.tcpdump /etc/apparmor.d/disable/
  • sudo /etc/init.d/apparmor restart

Temporarily Enabling Profile (using tcpdump which has a profile name of usr.sbin.tcpdump):

  • sudo apparmor_parser /etc/apparmor.d/usr.sbin.tcpdump

Permanently Re-enable Profile (using tcpdump which has a profile name of usr.sbin.tcpdump):

  • sudo rm /etc/apparmor.d/disable/usr.sbin.tcpdump
  • sudo /etc/init.d/apparmor restart

Creating/Editing Application Profiles

In the event that an application does not have a profile or we want to create an additional profile for an application AppArmor gives us that ability. For this part of the walkthrough we will be using apache2 as our application of choice to restrict. The first step in this process is to stop the apache2 service from running. We open up another terminal session to the same host and run the following command:

  • sudo service apache2 stop

Upon successfully stopping the apache2 service we now run the following command on our other terminal session:

  • sudo aa-genprof apache2

We can see from the output below that apache2 is waiting for the service to be started and the application to be used in order to ensure full functionality of the website:

   
acozzetta@ubuntu-server:~$ sudo aa-genprof apache2
Writing updated profile for /usr/sbin/apache2.
Setting /usr/sbin/apache2 to complain mode.

Before you begin, you may wish to check if a
profile already exists for the application you
wish to confine. See the following wiki page for
more information:
http://wiki.apparmor.net/index.php/Profiles

Please start the application to be profiled in
another window and exercise its functionality now.

Once completed, select the "Scan" option below in
order to scan the system logs for AppArmor events.

For each AppArmor event, you will be given the
opportunity to choose whether the access should be
allowed or denied.

Profiling: /usr/sbin/apache2

[(S)can system log for AppArmor events] / (F)inish

   

Jumping onto our other terminal session we start the apache2 service and go to the web address in our browser (this is done to ensure that the HTML page visited is given access):

  • sudo service apache2 start

When continuing with the profile scan we are able to see that apache2 is requesting access to the net_bind_server capability. We will allow this since it is a critical capability that apache2 needs.

   
Reading log entries from /var/log/syslog.
Updating AppArmor profiles in /etc/apparmor.d.
Complain-mode changes:

Profile:    /usr/sbin/apache2
Capability: net_bind_service
Severity:   8

 [1 - #include <abstractions/lxc/container-base>]
  2 - #include <abstractions/lxc/start-container>
  3 - #include <abstractions/nis>
  4 - capability net_bind_service,
(A)llow / [(D)eny] / (I)gnore / Audi(t) / Abo(r)t / (F)inish

   

Next we can see that apache2 needs access to apache2.conf. We will also allow this since it is critical for apache2 to have access to its own configuration file.

   
Adding #include <abstractions/lxc/container-base> to profile.

Profile:  /usr/sbin/apache2
Path:     /etc/apache2/apache2.conf
Mode:     r
Severity: 3

 [1 - /etc/apache2/apache2.conf]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore

   

There will be a lot that apache2 needs to access so it is important that you carefully look over what is necessary to prevent a potential security hole. After completing the process we can see that a profile for apache2 has been created in the /etc/apparmor.d directory as the filename usr.sbin.apache2.

   
acozzetta@ubuntu-server:/etc/apparmor.d$ pwd
/etc/apparmor.d

acozzetta@ubuntu-server:/etc/apparmor.d$ ls -l | grep apache2
drwxr-xr-x 2 root root  4096 Nov 27 13:24 apache2.d
-rw------- 1 root root  2368 Nov 27 13:38 usr.sbin.apache2

   

We can also see that the profile we created has been successfully loaded into AppArmor and is currently being enforced.

   
acozzetta@ubuntu-server:/etc/apparmor.d$ sudo apparmor_status
apparmor module is loaded.
55 profiles are loaded.
18 profiles are in enforce mode.
   /sbin/dhclient
   /usr/bin/lxc-start
   /usr/lib/NetworkManager/nm-dhcp-client.action
   /usr/lib/NetworkManager/nm-dhcp-helper
   /usr/lib/chromium-browser/chromium-browser//browser_java
   /usr/lib/chromium-browser/chromium-browser//browser_openjdk
   /usr/lib/chromium-browser/chromium-browser//sanitized_helper
   /usr/lib/connman/scripts/dhclient-script
   /usr/lib/snapd/snap-confine
   /usr/lib/snapd/snap-confine//mount-namespace-capture-helper
   /usr/sbin/apache2
   /usr/sbin/apache2//DEFAULT_URI
   /usr/sbin/apache2//HANDLING_UNTRUSTED_INPUT

4 processes have profiles defined.
4 processes are in enforce mode.
   /sbin/dhclient (1585)
   /usr/sbin/apache2 (2428)
   /usr/sbin/apache2 (2433)
   /usr/sbin/apache2 (2434)

   

Lets go ahead and inspect the configuration file located at /etc/apparmor.d/usr.sbin.apache2


# Last Modified: Sun Nov 27 13:38:18 2016
#include <tunables/global>

/usr/sbin/apache2 {
  #include <abstractions/base>
  #include <abstractions/lxc/container-base>

  /etc/apache2/apache2.conf r,
  /etc/apache2/conf-available/charset.conf r,
  /etc/apache2/conf-available/localized-error-pages.conf r,
  /etc/apache2/conf-available/other-vhosts-access-log.conf r,
  /etc/apache2/conf-available/security.conf r,
  /etc/apache2/conf-available/serve-cgi-bin.conf r,
  /etc/apache2/conf-enabled/ r,
  /etc/apache2/mods-available/access_compat.load r,
  /etc/apache2/mods-available/alias.conf r,
  /etc/apache2/mods-available/alias.load r,
  /etc/apache2/mods-available/auth_basic.load r,
  /etc/apache2/mods-available/authn_core.load r,
  /etc/apache2/mods-available/authn_file.load r,
  /etc/apache2/mods-available/authz_core.load r,
  /etc/apache2/mods-available/authz_host.load r,
  /etc/apache2/mods-available/authz_user.load r,
  /etc/apache2/mods-available/autoindex.conf r,
  /etc/apache2/mods-available/autoindex.load r,
  /etc/apache2/mods-available/deflate.conf r,
  /etc/apache2/mods-available/deflate.load r,
  /etc/apache2/mods-available/dir.conf r,
  /etc/apache2/mods-available/dir.load r,
  /etc/apache2/mods-available/env.load r,
  /etc/apache2/mods-available/filter.load r,
  /etc/apache2/mods-available/mime.conf r,
  /etc/apache2/mods-available/mime.load r,
  /etc/apache2/mods-available/mpm_event.conf r,
  /etc/apache2/mods-available/mpm_event.load r,
  /etc/apache2/mods-available/negotiation.conf r,
  /etc/apache2/mods-available/negotiation.load r,
  /etc/apache2/mods-available/setenvif.conf r,
  /etc/apache2/mods-available/setenvif.load r,
  /etc/apache2/mods-available/status.conf r,
  /etc/apache2/mods-available/status.load r,
  /etc/apache2/mods-enabled/ r,
  /etc/apache2/ports.conf r,
  /etc/apache2/sites-available/000-default.conf r,
  /etc/apache2/sites-enabled/ r,
  /etc/gai.conf r,
  /etc/group r,
  /etc/host.conf r,
  /etc/hosts r,
  /etc/mime.types r,
  /etc/nsswitch.conf r,
  /etc/passwd r,
  /run/apache2/apache2.pid w,
  /run/resolvconf/resolv.conf r,
  /usr/sbin/apache2 mr,
  /usr/share/apache2/icons/ubuntu-logo.png r,
  /var/log/apache2/access.log w,
  /var/log/apache2/error.log w,
  /var/log/apache2/other_vhosts_access.log w,
  /var/www/html/index.html r,


  ^DEFAULT_URI {
  }

  ^HANDLING_UNTRUSTED_INPUT {
  }
}

From this we can see what files and directories apache2 has access to. One important file is the HTML homepage itself, /var/www/html/index.html r,. The r denotes that apache2 has read access to this file. Below are the file file permission options available to be configured:

   
r - read
w - write
a - append (implied by w)
x - execute
   

Lets break the website and intentionally remove access to this file by adding the deny keyword before that line. The first thing we need to do is temporarily unload the apache2 profile from AppArmor in order to edit it. Run the following command to do that:

  • sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.apache2

We can see below that the apache2 process is no longer loaded by AppArmor (output trimmed):

   
acozzetta@ubuntu-server:/etc/apparmor.d$ sudo apparmor_status
1 processes are in enforce mode.
   /sbin/dhclient (1630)
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
   

Lets go ahead and edit the /etc/apparmor.d/usr.sbin.apache2 file to deny access to the HTML homepage.

   
deny /var/www/html/index.html r,
   

Now lets re-enable the apache2 profile by running the following command:

  • sudo apparmor_parser /etc/apparmor.d/usr.sbin.apache2

After reloading the homepage we can see that apache2 no longer has access to read that file.

   
Forbidden

You don't have permission to access /index.html on this server.
Apache/2.4.18 (Ubuntu) Server at 192.168.223.134 Port 80
   

We can also use wildcards to deny access to entire directories such as the following:

   
deny /var/www/html/* r,
   

It is also important to note that manually created AppArmor profiles are default deny, meaning that anything resources not listed in the profile are denied access to the application. We could just have easily removed the /var/www/html/index.html r line from the configuration and had the effect as explicitly denying access to the file.

Summary

As you can see AppArmor is a very powerful and easy to understand security module allowing us to quickly and effectively limit the permissions of our applications. Limiting the permissions our applications have can greatly decrease the damage done in the event our applications being compromised. In our next topic we will cover SELinux and it’s configuration process and procedure to better secure our system.


SELinux:

SELinux is a Mandatory Access Control (MAC) Linux Security Module (LSM) developed by the NSA and Red Hat. It allows administrators to finely tune accessible application and user resources. Just like AppArmor, SELinux is extremely useful in the event an application becomes compromised by limiting the permissions and systems resources available to the application. Below are the topics we are going to cover for SELinux:

  • Installation
  • Checking SELinux Status
  • Changing SELinux Modes of Operation
  • Intro to SELinux Users, Roles, and Domains
  • Enabling and Disabling SELinux Modules
  • Creating Policies
  • Summary

Installation

Note: For this tutorial we will be using CentOS 7 which already includes SELinux

Though SELinux is already installed there are packages we should install to better manage SELinux. These packages include policycoreutils-python (which allows us to manage SELinux) and setools-console (provides tools for audit log monitoring, querying policy, and file context management). Run the following commands to install these packages:

  • sudo yum install policycoreutils-python -y
  • sudo yum install setools-console -y

Checking SELinux Status

The running status of SELinux can be seen using any of the following commands:

  • sestatus
  • cat /etc/selinux/config
  • getenforce
   
[acozzetta@localhost ~]$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Max kernel policy version:      28


[acozzetta@localhost ~]$ cat /etc/selinux/config

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of three two values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected.
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted

[acozzetta@localhost ~]$ getenforce
Enforcing
   

/etc/selinux/config is the configuration file used to change the security modes of SELinux as well as disable SELinux. From this output we can see that SELinux is both enabled and enforcing. Next we will go into the different modes of operation for SELinux.

Changing SELinux Modes of Operation

SELinux can operate in one of the following three modes at a single time (unlike AppArmor which allows each application to run with different operating modes):

  • Enforcing: SELinux security policies are enforced. If actions are supposed to be denied they will be. The actions will be logged to /var/log/audit/audit.log
  • Permissive: SELinux prints warnings instead of enforcing. If actions are supposed to be denied they will not be. The actions will be logged to /var/log/audit/audit.log
  • Disabled: No SELinux policies are loaded. If actions are supposed to be denied they will not be. The actions will not be logged

Putting SELinux into Permissive mode and reading the output logs can be a great help to administrators when SELinux is the cause of unintentional denied permissions.

Note: It is best practice and sometimes even necessary to reboot your host after changing the operating mode of SELinux

To change the mode of SELinux to Enforcing run the following command/make the following edit:

  • sudo setenforce 1
  • Edit the /etc/selinux/config so that the SELINUX=xxx line read SELINUX=enforcing. When done save and quit the file

To change the mode of SELinux to Permissive run the following command/make the following edit:

  • sudo setenforce 0
  • Edit the /etc/selinux/config so that the SELINUX=xxx line read SELINUX=permissive. When done save and quit the file

To change the mode of SELinux to Disabled make the following edit:

  • Edit the /etc/selinux/config so that the SELINUX=xxx line read SELINUX=disabled. When done save and quit the file

Intro to SELinux Users, Roles, and Domains

Before we can go into policy creation we first need to go over the terminology for SELinux policies. SELinux breaks down contexts into three main categories:

  • Users: Every user account on the computer is linked to only one SELinux user
  • Roles: Define which SELinux user identities can have access to what domains
  • Domains: Used to group together a number of processes/applications to apply permissions

By running the sudo semanage user -l command we are able to see the list of available SELinux users and roles:

   
[acozzetta@localhost ~]$ sudo semanage user -l

                Labeling   MLS/       MLS/
SELinux User    Prefix     MCS Level  MCS Range                      SELinux Roles

guest_u         user       s0         s0                             guest_r
root            user       s0         s0-s0:c0.c1023                 staff_r sysadm_r system_r unconfined_r
staff_u         user       s0         s0-s0:c0.c1023                 staff_r sysadm_r system_r unconfined_r
sysadm_u        user       s0         s0-s0:c0.c1023                 sysadm_r
system_u        user       s0         s0-s0:c0.c1023                 system_r unconfined_r
unconfined_u    user       s0         s0-s0:c0.c1023                 system_r unconfined_r
user_u          user       s0         s0                             user_r
xguest_u        user       s0         s0                             xguest_r

   

Users can tell which SELinux user, role, and domain they are mapped to by running the id -Z command. Below we can see that we are mapped to the unconfined user, unconfined role, and unconfined domain:

   
[acozzetta@localhost ~]$ id -Z
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
   

What user accounts are mapped to determines access control capabilities (guest_u is most locked down)

To change the SELinux user mapping of a user account use the following command (where USERNAME is the name of the user you want to change the context of and SELINUX_USER is an available SELinux user context):

  • sudo semanage login -a -s SELINUX_USER USERNAME

For example:

   
sudo semanage login -a -s guest_u root
   

We have now successfully locked down the root account with guest_u privileges. When logging into the root account we can run the id -Z command to see that our user context has successfully changed to that of a guest user:

   
-bash-4.2# whoami
root
-bash-4.2# id -Z
guest_u:guest_r:guest_t:s0

   

Enabling and Disabling SELinux Modules

SELinux uses modules to load permission configurations. To view the list of loaded modules run the following command:

  • sudo semodule -l
   
[root@localhost acozzetta]# semodule -l
abrt    1.4.1
accountsd       1.1.0
acct    1.6.0
afs     1.9.0
aiccu   1.1.0
aide    1.7.1
ajaxterm        1.0.0
alsa    1.12.2
amanda  1.15.0
amtu    1.3.0
anaconda        1.7.0
antivirus       1.0.0
apache  2.7.2
apcupsd 1.9.0
apm     1.12.0
application     1.2.0
arpwatch        1.11.0
asterisk        1.12.1
auditadm        2.2.0
authconfig      1.0.0
authlogin       2.5.1
automount       1.14.1
   

To disable a module run the following command:

  • semodule -d MODULE_NAME_HERE

Note: Disabling a module using this method survives reboots

To enable a module run the following command:

  • semodule -e MODULE_NAME_HERE

To remove a module run the following command:

  • semodule -r MODULE_NAME_HERE

Creating Policies

SELinux polices can be created manually and/or automatically. In this tutorial we are going to focus on the automatic creation of policies using a utility called audit2allow. Audit2allow works very similar to AppArmor aa-genprof by reading logs and creating polices from them. Audit2allow creates allow polices from the SELinux error logs contained inside /var/log/audit/audit.log. Below are are the commands necessary to create and load policies created from audit2allow:

  • audit2allow -M my_policy < /var/log/audit/audit.log
  • semodule -i my_policy.pp

audit2allow -M my_policy < /var/log/audit/audit.log is responsible for creating the .te and .pp files. .te files are Type Enforcement files. These files list the actual human readable policies whereas the .pp files are compiled from the .te file for SELinux to interpret and load. Below are the contents of the audit log to my_policy.te file created from the first command:

   
[root@localhost Policies]# cat /var/log/audit/audit.log | grep AVC
type=AVC msg=audit(1480296701.205:101): avc:  denied  { write } for  pid=2344 comm="bash" name=".bash_history" dev="dm-0" ino=134340320 scontext=guest_u:guest_r:guest_t:s0 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file
type=AVC msg=audit(1480296701.205:102): avc:  denied  { append } for  pid=2344 comm="bash" name=".bash_history" dev="dm-0" ino=134340320 scontext=guest_u:guest_r:guest_t:s0 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file
type=AVC msg=audit(1480296701.207:105): avc:  denied  { net_admin } for  pid=2338 comm="sshd" capability=12  scontext=guest_u:guest_r:guest_t:s0 tcontext=guest_u:guest_r:guest_t:s0 tclass=capability
type=AVC msg=audit(1480296701.207:106): avc:  denied  { net_admin } for  pid=2338 comm="sshd" capability=12  scontext=guest_u:guest_r:guest_t:s0 tcontext=guest_u:guest_r:guest_t:s0 tclass=capability
type=AVC msg=audit(1480296701.207:107): avc:  denied  { write } for  pid=2338 comm="sshd" name="system_bus_socket" dev="tmpfs" ino=15927 scontext=guest_u:guest_r:guest_t:s0 tcontext=system_u:object_r:system_dbusd_var_run_t:s0 tclass=sock_file
type=USER_AVC msg=audit(1480299615.650:130): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='avc:  received policyload notice (seqno=2)  exe="/usr/lib/systemd/systemd" sauid=0 hostname=? addr=? terminal=?'
type=AVC msg=audit(1480299615.663:131): avc:  denied  { write } for  pid=2305 comm="bash" name=".bash_history" dev="dm-0" ino=134340320 scontext=guest_u:guest_r:guest_t:s0 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file
type=AVC msg=audit(1480299615.663:132): avc:  denied  { append } for  pid=2305 comm="bash" name=".bash_history" dev="dm-0" ino=134340320 scontext=guest_u:guest_r:guest_t:s0 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file



module my_policy 1.0;

require {
        type admin_home_t;
        type system_dbusd_var_run_t;
        type guest_t;
        class sock_file write;
        class capability net_admin;
        class file { write append };
}

#============= guest_t ==============
allow guest_t admin_home_t:file { write append };
allow guest_t self:capability net_admin;
allow guest_t system_dbusd_var_run_t:sock_file write;
   

Above we can see the policies in the .te file which were created from the AVC messages in audit.log. AVC messages are specific to SELinux which is why we did a grep for AVC.

The final step is to run the semodule -i my_policy.pp command. This will load the .pp file into the available SELinux module list and enable the module in SELinux. We can see below that running the command to list the modules shows our newly created module:

   
[root@localhost Policies]# semodule -l | grep my_policy
my_policy       1.0
   

Note: You should always inspect your generated .te files before loading the module into SELinux to be sure that you are not opening up potential security holes.

Summary

Though more complex to configure than AppArmor, SELinux provides us with a lot more options to “tune” the permissions for our applications. SELinux uses security contexts (which every filesystem object has) whereas AppArmor uses file paths. Using these security contexts makes configuration more difficult to understand, but as mentioned provides administrators the ability to be more specific with permissions.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s