Web applications will have flaws, and those flaws will lead to unauthorized access. We can mitigate the risks of a vulnerable website by restricting the website’s access rights on the server. So in the event of a compromise, we will confine the damage to one website and not the whole server.

To limit a single website’s access rights we will deploy AppArmor. AppArmor is a program that configures Mandatory Access Controls within the Ubuntu Kernel.

Mandatory Access Control

Mandatory Access Controls(MAC) is a security mechanism that restricts the level of control a user has over objects that they create. Default Linux installations use Discretionary Access Control(DAC), which is less secure than MAC.

Unlike in the DAC default, where users have full control over their own files, directories, etc., MAC adds additional labels, or categories, to all file system objects. Users and processes must have the appropriate access to these categories before they can interact with these objects. Depending on your Linux flavor, you can add MACs with either SELinux or AppArmor.

More on DAC v.s. MAC if you are interested.

This article is the fifth in the Diamond Hard LAMP series.

The Basics of AppArmor

Our goal is to use AppArmor to secure our LAMP webserver. In the case of web servers, AppArmor protects our server even if a web application has a vulnerability. To do this each application needs to have an accompanying “profile” that defines what access the application has. If an application tries to access something not defined in the profile, it will be denied.

We will need two profiles for a web server. The first is a profile for the Apache process itself. The other is a sub-profile of the Apache profile for the unique website. If our server is hosting multiple websites, then we need a unique sub-profile for each site. We need this sub-profile because a single website should not have the same access the Apache service has, instead it needs to be more limited.

AppArmor is a big subject and I could not cover it all within this one post. Below I have listed the resources that I found helpful when first getting started.

Once you feel you have the basic understanding of AppArmor, you can move on to installing and configuring it.

Installing AppArmor

We will start by installing the core packages needed to run AppArmor with our LAMP server. This includes the AppArmor Profiles, AppArmor utility applications, and the Apache2 AppArmor module.

# Update and upgrade.
apt update && apt -y upgrade
# Install the packages
apt install apparmor-profiles apparmor-utils libapache2-mod-apparmor

Now we need to tell AppArmor to enforce the Apache default profile. We also will enable the Apache modules required for Apache to speak with AppArmor.

aa-enforce /etc/apparmor.d/usr.sbin.apache2
a2enmod mpm_prefork
a2enmod apparmor

Lastly, we need to set AppArmor to run at boot time and then reload AppArmor and Apache services.

systemctl enable apparmor
systemctl reload apparmor.service apache2.service

AppArmor Most Commonly Needed Commands

Let’s review the commands that control AppArmor before we continue on to configurations. There are a few commands that you will be using frequently, so I want to highlight them here.


Display various information about the current AppArmor policy. You will be using this command a lot to confirm the state of your configurations.

# Example
$> aa-status


This will set an AppArmor security profile from being in disabled or complain mode, to enforce mode.

# Example
$> aa-enforce /etc/apparmor.d/usr.sbin.apache2


Disable an AppArmor security profile. This can be very helpful when troubleshooting if an issue is caused by AppArmor or by some other component.

# Example
$> aa-disable /etc/apparmor.d/usr.sbin.apache2


Set an AppArmor security profile to complain mode. In this mode, security policies are not enforced but rather access violations are logged to the system log.

# Example
$> aa-complain /etc/apparmor.d/usr.sbin.apache2


Used as a general tool to compile, and manage AppArmor policy, including loading new AppArmor profiles into the Linux kernel. The profiles may be specified by file name or a directory name containing a set of profiles.

Here are the most common uses of this command.

# '-r' option, used to replace the definition already in the kernel
$> apparmor_parser -r /etc/apparmor.d/usr.sbin.apache2

# '-R' This flag is used to remove an AppArmor definition already in the kernel.
$> apparmor_parser -R /etc/apparmor.d/usr.sbin.apache2

# '-a' option, used to insert a AppArmor definitions given into the kernel.
$> apparmor_parser -a /etc/apparmor.d/usr.sbin.apache2

Configuring AppArmor Hats for a Website

AppArmor secures our LAMP server confining the Apache process and resource access. However, a single individual website should have a more restrictive set of access controls than the whole Apache instance. To further restrict a website running within Apache we need to create a sub-profile, or “Hat”. To add a sub-profile for a website we need to create and edit a few files.

Here is an example of a sub-profile for the site “dev.cybergladius.com”. Take note that you will need to change this based on the settings and access rights your site needs.

Store all sub-profile configurations in the “/etc/apparmor.d/apache2.d/” directory. I will create a new file at “/etc/apparmor.d/apache2.d/dev.cybergladius.com-aa”; the file name does not really matter.

^dev_cybergladius_com {

# These directive pulls in components of AppArmor profiles to simplify profiles.
    #include <abstractions/apache2-common>
    #include <abstractions/base>
    #include <abstractions/php>

# Allow Read/Write access to all files/dirs, sub-files/dirs of /home/cg_dev/wwwroot/
    /home/cg_dev/wwwroot/** rw,

# Allow read olny access to the file ".htpasswd", used for .htaccess use logins.
    /home/cg_dev/.secret/.htpasswd r,

# Allow write only access to the log files.
    /home/cg_dev/wwwroot/dev.cybergladius.com_access.log w,
    /home/cg_dev/wwwroot/dev.cybergladius.com_error.log w,
    /home/cg_dev/wwwroot/dev.cybergladius.com_modsec.log w,

Note the “^” character, this indicates the start of a new sub-profiles/Hat. Following the “^” is the sub-profile name. In this example, the sub-profiles/Hat name is “dev_cybergladius_com”. You will need this information for the next part.

With the AppArmor configuration added we now need to tell Apache to use the sub-profile for our website. We do this by editing the website’s Apache configuration file; in my case “/etc/apache2/sites-enabled/dev.cybergladius.com.conf”.

We need to add the directive “AADefaultHatName <Sub-Profile_Name>” in-between the “<VirtualHost>” directives. See the example below.

# HTTPS site Config for dev.cybergladius.com
<IfModule mod_ssl.c>
		<VirtualHost _default_:443>
		ServerAdmin [email protected]
		ServerName dev.cybergladius.com
		SecRuleEngine On
		DocumentRoot /home/cg_dev/wwwroot/
		AADefaultHatName dev_cybergladius_com
		<Directory /home/cg_dev/wwwroot/>
			AllowOverride All
			Require all granted
		SSLEngine on
		SSLCertificateFile /home/cg_dev/ssl/dev.cybergladius.com.crt
		SSLCertificateKeyFile /home/cg_dev/ssl/dev.cybergladius.com.key
		SSLCertificateChainFile /home/cg_dev/ssl/dev.cybergladius.com.crt
		<FilesMatch "\.(cgi|shtml|phtml|php)$">
				SSLOptions +StdEnvVars
		<Directory /usr/lib/cgi-bin/>
				SSLOptions +StdEnvVars
		LogLevel warn
		ErrorLog /home/cg_dev/logs/dev.cybergladius.com_error.log
		CustomLog /home/cg_dev/logs/dev.cybergladius.com_access.log combined
		SecAuditLog /home/cg_dev/logs/dev.cybergladius.com_modsec.log

Applying Changes

Now we have all the configurations in place we just need to apply them.

Start by reloading the AppArmor configuration for Apache, this will also load everything within the “/etc/apparmor.d/apache2.d/” directory.

apparmor_parser -r /etc/apparmor.d/usr.sbin.apache2

Lastly, we need to reload Apache so it sees our new configuration changes.

 systemctl reload apache2.service

Everything should be working now when you navigate to the website!

If you need more examples of AppArmor Hat profiles setting review this wiki page.