Skip to content

Instantly share code, notes, and snippets.

@Determinant
Created July 8, 2014 13:50
Show Gist options
  • Save Determinant/7ec0400e9be60364f94e to your computer and use it in GitHub Desktop.
Save Determinant/7ec0400e9be60364f94e to your computer and use it in GitHub Desktop.

How to Configure AppArmor on Ubuntu

Author: Ted Yin <[email protected]>
  • AppArmor is a Mandatory Access Control (MAC) system which is a kernel (LSM) enhancement to confine programs to a limited set of resources. Instead of binding access control attributes to users, it confines specific programs.

  • AppArmor is shipped with Ubuntu, which means it is fairly easy to get started.

  • In order to ease the maintenance, we first install the utilities by sudo apt-get install apparmor-utils

  • To demonstrate the typical use of AppArmor, we try to confine the behavior of the Python interpreter:

    • First, to avoid system-wide change, we make a duplicate of the Python interpreter binary:

      sudo -i
      cd  # The working directory in this example is under /root
      cp /usr/bin/python confined_python
      

      Note that we have to copy the file instead of simply creating a symbolic link because AppArmor does not support symbolic links. See [1]

    • Then, we make use of aa-autodep to generate a initial configuration of confined_python:

      aa-autodep confined_python
      
    • Next, we can edit the configuration file located at /etc/apparmor.d/root.confined_python. The naming rule is to substitute all intermediate slashes in the path name of the program to dots, for example: /this/is/a/path corresponds to this.is.a.path.

    • For demonstration, we do not change the content of configuration, which leads to the strictest control. It is worth noticing that there are two working modes in AppArmor, one is called "complain", while the other is "enforce". As the name suggests, only the latter mode actually confines the behavior of a program. So we shall turn on the "enforce" mode:

      aa-enforce confined_python
      
    • Now we can start the program to see the result:

      ./confined_python
      

      You can try to test whether AppArmor becomes effective by opening a file, sending a HTTP request, or spawning a subprocess in Python, if the default configuration works correctly, all permission invoked by these operations is denied:

      >>> f = open("test.out", "w")
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      PermissionError: [Errno 13] Permission denied: 'test.out'
      Error in sys.excepthook:
      Traceback (most recent call last):
        File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 63, in apport_excepthook
          from apport.fileutils import likely_packaged, get_recent_crashes
        File "/usr/lib/python3/dist-packages/apport/__init__.py", line 5, in <module>
          from apport.report import Report
        File "/usr/lib/python3/dist-packages/apport/report.py", line 30, in <module>
          import apport.fileutils
        File "/usr/lib/python3/dist-packages/apport/fileutils.py", line 23, in <module>
          from apport.packaging_impl import impl as packaging
        File "/usr/lib/python3/dist-packages/apport/packaging_impl.py", line 20, in <module>
          import apt
        File "/usr/lib/python3/dist-packages/apt/__init__.py", line 23, in <module>
          import apt_pkg
      ImportError: /usr/lib/python3/dist-packages/apt_pkg.cpython-34m-x86_64-linux-gnu.so: failed to map segment from shared object: Permission denied
      
      >>> import httplib
      >>> conn = httplib.HTTPConnection('www.tedyin.com')
      >>> conn.request('GET', '/index.html')
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "/usr/lib/python2.7/httplib.py", line 973, in request
          self._send_request(method, url, body, headers)
        File "/usr/lib/python2.7/httplib.py", line 1007, in _send_request
          self.endheaders(body)
        File "/usr/lib/python2.7/httplib.py", line 969, in endheaders
          self._send_output(message_body)
        File "/usr/lib/python2.7/httplib.py", line 829, in _send_output
          self.send(msg)
        File "/usr/lib/python2.7/httplib.py", line 791, in send
          self.connect()
        File "/usr/lib/python2.7/httplib.py", line 772, in connect
          self.timeout, self.source_address)
        File "/usr/lib/python2.7/socket.py", line 553, in create_connection
          for res in getaddrinfo(host, port, 0, SOCK_STREAM):
      socket.gaierror: [Errno -2] Name or service not known
      
      >>> import subprocess
      >>> subprocess.check_call(["ls", "-l"])
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "/usr/lib/python2.7/subprocess.py", line 535, in check_call
          retcode = call(*popenargs, **kwargs)
        File "/usr/lib/python2.7/subprocess.py", line 522, in call
          return Popen(*popenargs, **kwargs).wait()
        File "/usr/lib/python2.7/subprocess.py", line 710, in __init__
          errread, errwrite)
        File "/usr/lib/python2.7/subprocess.py", line 1327, in _execute_child
          raise child_exception
      OSError: [Errno 13] Permission denied
      
[1]http://serverfault.com/questions/290828/creating-a-linux-sandbox-with-apparmor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment