SELinux and AppArmor

They both are security related technologies classified as MAC - Mandatory Access Control. SELinux was created by NSA - National Security Agency, while AppArmor become popular after it has adopted by Ubuntu Linux.

The main idea here is to create mechanisms to extend the basic permission schema based on ugo/rwx. Among other things, they offer the ability to restrict access by system process to files, directories, network ports, etc.

AppArmor offers an autolearn mode, which is capable to know how a system should operate, while SELinux brings an enforcing mode by default since CentOS 6.


SELinux stands for Security Enhanced Linux and it can operate in two modes:

  • enforcing: SELinux will deny access based on its policy rules, a set of guidelines that control its engine.
  • permissive: SELinux won't deny access, but denials will be logged for actions that would have been denied if running in enforcing mode.

You have the choice to completely disable SELinux, however, it is not recommended these days! It's better to learn how to take advantage of this excellent tool.

You can verify the current operation mode of SELInux using getenforce command, and you can change it by setenforce 0 - permissive mode - or setenforce 1 - enforcing mode. To persist this change across reboots you need to set the SELINUX variable in the /etc/selinux/config file.

To set SELINUX from or to disabled mode you will have to edit the above file and reboot your system.

As a common use case lets see how to change the SSH daemon port from 22 to 2222:

  1. Make sure you have the policycoreutils-python package installed:

    yum install -y policycoreutils-python
  2. Tell SELinux that port 2222 is allowed to be used by ssh process:

    # check all ports managed by SELinux
    selinux port -l
    # Customize ssh to run on port 2222/tcp
    semanage port -a -t ssh_port_t -p tcp 2222
    # check all customized ports managed by SELinux
    semanage -lC

    Another common scenario is to change the default allowed DocumentRoot folder to be used by a web server. Lets add the /srv/www to the list of the allowed directories:

semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"

The above command will grant apache read-only access to that directory and its contents.

Finally, to apply the pilicy, making the label change effective immediately):

restorecon -R -v /srv/www

If things are still not working as expected you can look for AVC string in /var/log/audit/audit.log file.

You can get more help at SELinux Official Documentation.


AppArmor uses profiles defined in text files instead of policy managed by commands. There are several of them provided out of the box. These profiles are available at /etc/apparmod.d.

You can check the AppArmor current status by running:


To switch a profile between complain and enforce modes, like smbd profile, we can run:

aa-complain /etc/apparmor.d/usr.sbin.smbd
aa-enforce  /etc/apparmor.d/usr.sbin.smbd

The above commands also accept bash wildcards to change multiple profiles at once.

To entirely disable a profile, we just have to create a link to its file at /etc/apparmor.d/disable/ directory, like so:

sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/

You can get more information for AppArmor in Ubuntu AppArmor Community Documentation.

Keith Mills's photo

Hello Rodrigo,

I'm quite new to AppArmor but I'm really excited to learn all that I can! I've read your article on SELinux and AppArmor. I see that you mention complain and enforce modes but not permissive mode! Does this mean that there isn't a permissive mode? Also, you mentioned AppArmor uses profiles defined in text files instead of policy managed by commands. My question is:

For SLSE 15-SP1 how would I set the mode using an Ansible task if this is possible?

This is what I have so far:

  • name: install selinux dependencies when selinux is installed on Debian apt: name: ['policycoreutils', 'checkpolicy', 'selinux-basics', 'python-selinux' ] state: present when: ansible_distribution|lower == 'debian'
  • name: Set SELinux to permissive mode | RHEL selinux: policy: targeted state: permissive register: task_result when: ansible_distribution|lower == 'redhat'
  • name: Set SELinux to permissive mode | Debian selinux: policy: default state: permissive register: task_result when:
    • ansible_selinux_python_present|bool
    • ansible_distribution|lower == 'debian'
  • name: Reboot the server and wait for it to come back up. reboot: when: task_result is changed ...

As you can see, i don't have a task for AppArmor! If you can help me I would greatly appreciate it!