How to configure AppArmor for PostgreSQL and TimescaleDB

Sebastian Insausti

Security is a must for all systems to protect your data as much as possible. Even when there is always a risk to be hacked, by following a security checklist will reduce this risk significantly. A basic security checklist includes a firewall configuration, data encryption, authentication policy, etc. Another important tool to protect your data on Debian-Based operating systems is AppArmor. In this blog, we will see what is and how to configure it for PostgreSQL and TimescaleDB databases.

What is AppArmor?

AppArmor, included by default in Ubuntu and Debian (among others) operating systems, is a Mandatory Access Control (MAC) system to confine programs to a limited set of resources. It works using profiles loaded into the kernel. These profiles can be configured in two modes:

  • Enforcement: The profiles loaded in this mode will enforce the policy defined in the profile as well as reporting policy violation attempts.

  • Complain: The profiles in this mode will not enforce policy but instead report policy violation attempts.

Also, AppArmor allows the mixing of enforcement and complain mode profiles.

How to Configure AppArmor

The AppArmor profiles are in /etc/apparmor.d/. You can create your own profiles and move them there or check the AppArmor repository. Let’s see how to create a new AppArmor profile. 

First, let’s install the necessary packages to handle this:

$ apt install apparmor-profiles apparmor-utils

And see if AppArmor is enabled:

$ systemctl status apparmor.service

or

$ aa-status
apparmor module is loaded.
31 profiles are loaded.
29 profiles are in enforce mode.
   /snap/snapd/11588/usr/lib/snapd/snap-confine
   /snap/snapd/11588/usr/lib/snapd/snap-confine//mount-namespace-capture-helper
  ...

If you check the mentioned path /etc/apparmor.d/, you will see some basic profiles like usr.sbin.tcpdump, or usr.sbin.traceroute. Now, let’s create a new profile for PostgreSQL or TimescaleDB. For this, you can use this profile as an example. Based on that profile, we will replace the PostgreSQL version to be more specific. In this case, we will use PostgreSQL 13.

# Author: Felix Geyer <[email protected]>
#include <tunables/global>
/usr/lib/postgresql/13/bin/postgres {
  #include <abstractions/base>
  #include <abstractions/nameservice>
  #include <abstractions/ssl_keys>
  /etc/postgresql/** r,
  /usr/share/postgresql/** r,
  /var/lib/postgresql/** rwl,
  /{,var/}run/postgresql/** rw,
  owner @{PROC}/13/oom_adj rw,
}

Store it in /etc/apparmor.d/usr.lib.postgresql.13.bin.postgres. Then, load the new profile using apparmor_parser -a:

$ cat /etc/apparmor.d/usr.lib.postgresql.13.bin.postgres | sudo apparmor_parser -a

If you want to change something on this profile, you will need to reload it:

$ apparmor_parser -r /etc/apparmor.d/usr.lib.postgresql.13.bin.postgres

You can assign the Complain mode to the profile by using the following command:

$ aa-complain /usr/lib/postgresql/13/bin/postgres

Then, you can check the syslog file in /var/log to see if the AppArmor configuration is correct, or you need to modify something. When it is safe, you can change the mode to Enforce by running:

$ aa-enforce /usr/lib/postgresql/13/bin/postgres

You can filter the log looking for ALLOWED or DENIED actions:

Jun 25 19:48:02 ip-172-31-18-94 kernel: [ 5160.111028] audit: type=1400 audit(1624650482.537:103): apparmor="ALLOWED" operation="open" profile="/usr/lib/postgresql/13/bin/postgres" name="/proc/17405/oom_score_adj" pid=17405 comm="postgres" requested_mask="w" denied_mask="w" fsuid=113 ouid=113

Jun 25 19:48:02 ip-172-31-18-94 kernel: [ 5160.112524] audit: type=1400 audit(1624650482.541:104): apparmor="ALLOWED" operation="open" profile="/usr/lib/postgresql/13/bin/postgres" name="/proc/17404/oom_score_adj" pid=17404 comm="postgres" requested_mask="w" denied_mask="w" fsuid=113 ouid=113

Jun 25 19:50:02 ip-172-31-18-94 kernel: [ 5280.141262] audit: type=1400 audit(1624650602.569:112): apparmor="DENIED" operation="open" profile="/usr/lib/postgresql/13/bin/postgres" name="/proc/17518/oom_score_adj" pid=17518 comm="postgres" requested_mask="w" denied_mask="w" fsuid=113 ouid=113

You can also disable profiles in this way:

$ aa-disable /etc/apparmor.d/usr.lib.postgresql.13.bin.postgres

And you will need to reload the service:

$ systemctl reload apparmor.service

In case you prefer to disable AppArmor, you can run:

$ systemctl stop apparmor
$ systemctl disable apparmor

Of course, this is not recommended for production environments, and you should keep it running, at least, using the Complain mode in all the profiles, so you can check the logs looking for unexpected behavior.

How to use PostgreSQL and TimescaleDB with ClusterControl and AppArmor

ClusterControl doesn’t manage any Linux kernel security modules like AppArmor. When deploying a PostgreSQL or TimescaleDB cluster by using ClusterControl, you can specify if you want ClusterControl to disable AppArmor for you during the deployment process to reduce the risk of errors:

If you don’t want to disable it, which is recommended for production environments, you can use the Complain mode and monitor the log in your servers to make sure that you have the correct AppArmor configuration. After that, you can change it to Enforce following the instructions mentioned above.

You can find more information about the AppArmor configuration on the Ubuntu official site.

ClusterControl
The only management system you’ll ever need to take control of your open source database infrastructure.