Alcide Rapid 7 Logo Alcide Rapid 7 Logo
Alcide has been acquired by Rapid7- a leading provider of security analytics and automation. Learn more

Whitelisting Processes on Kubernetes Pods Using AppArmor (Part 1)

August 12, 2020
Natan Yellin
Senior Software Engineer

Here is an underappreciated fact about Docker images and therefore Kubernetes pods: every pod runs very few processes. In fact, many pods run only one single process and all the details of that process are known in advance. This makes defending a Kubernetes cluster drastically different from defending a traditional Linux server. As a Kubernetes defender, you have a critical advantage because you know exactly what code a pod should be running down to the last binary. Therefore, it is possible to lockdown pods and prevent them from running unwanted and malicious code.

In practice, enforcing process whitelists in Kubernetes is no easy task.
In this two part series, we will look at how you can implement process whitelisting for Kubernetes using AppArmor profiles. In this first part of the series we’ll explain how AppArmor is already used by Kubernetes and Docker.

AppArmor and Kubernetes

AppArmor is a popular security module for Linux which allows restricting the actions that processes can do in order to harden systems. It has been around for more than 22 years. Linux distributions like Ubuntu ship with AppArmor enabled by default and include pre-built profiles for popular applications.

In the cloud computing context, it makes sense to apply AppArmor profiles to specific containers in order to limit the malicious actions that an attacker could take if that container was breached. For a long time, Kubernetes has had beta support for applying specific AppArmor profiles to specific containers. It is important to realize that these profiles override the default AppArmor profile that Docker (and other container runtimes used by Kubernetes) will apply to your container if it doesn’t have a profile. Therefore, if you apply a custom AppArmor profile which is less restrictive than the default Docker profile you are actually weakening your pod’s security and not strengthening it.

The Default AppArmor Profile for Kubernetes/Docker

Let’s take a look at the default Docker profile which is generated from this template. For clarity’s sake, I’ve removed the templating tags and made minor tweaks to the profile. I’ve also broken it up into several parts with an explanation after each one. Here is the beginning of the profile:

profile profile_name flags=(attach_disconnected,mediate_deleted) {





signal (receive) peer={{.DaemonProfile}},

signal (send,receive) peer={{.Name}},

The first thing to understand is that AppArmor profiles start with a blank slate where nothing is allowed and every directive above specifies something that should be allowed. So the above snippet allows our container to access APIs like umount and signal as well as allowing broad access to the network and filesystem without restriction – that is, without AppArmor restrictions.

Our container’s access to the network and filesystem will still be limited by factors external to AppArmor like Linux network namespaces as well as override restrictions that appear later in the AppArmor profile. A rule like file is really shorthand for the rule allow file. You prefix all the rules with the keyword allow if you prefer and it will still be valid AppArmor syntax.

Let’s look at the next part of the profile which does indeed lockdown filesystem access a little more:

# deny write for all files directly in /proc (not in a subdir)

deny /proc/* w,

# deny write to files not in /proc/<number>/** or /proc/sys/**

deny /proc/{[^1-9],[^1-9][^0-9],[^1-9s][^0-9y][^0-9s],[^1-9][^0-9][^0-9][^0-9]*}/** w,

# deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel)

deny /proc/sys/[^k]** w,

# deny everything except shm* in /proc/sys/kernel/

deny /proc/sys/kernel/{?,??,[^s][^h][^m]**} w,

deny /proc/sysrq-trigger rwklx,

deny /proc/kcore rwklx,

deny mount,

deny /sys/[^f]*/** wklx,

deny /sys/f[^s]*/** wklx,

deny /sys/fs/[^c]*/** wklx,

deny /sys/fs/c[^g]*/** wklx,

deny /sys/fs/cg[^r]*/** wklx,

deny /sys/firmware/** rwklx,

deny /sys/kernel/security/** rwklx,


# suppress ptrace denials when using ‘docker ps’ or using ‘ps’ inside a container

ptrace (trace,read,tracedby,readby) peer={{.Name}},



The deny keyword used above lets you write rules that override the allowed operations specified elsewhere in the profile. What matters isn’t the order of the allow/deny directives in the file. If we put our deny rules at the start of the profile, the profile’s meaning wouldn’t change. Rather, AppArmor calculates profiles in three stages. First it creates an empty profile. Then it allows everything specified in allow-type rules anywhere in the profile. Then it overrides those allowed rules with deny rules no matter where they appear in the profile.

Let’s take a closer look at one of the filesystem rules:

deny /proc/kcore rwklx

There are three parts of this rule. First, the deny keyword, then a path, and finally the permissions to deny for that path. r stands for read, w for write, k relates to locking permissions, l relates to link files, and x is for execution permissions. Lastly, AppArmor syntax has all sorts of ugly shortcuts, but a more explicit way to write this rule would be as follows:

deny file /proc/kcore rwklx


Let’s take one more look at this rule from the beginning of the docker profile:




This rule relies on a lot of implicit defaults in AppArmor’s syntax, like the fact that rules with no prefix are allow by default, that rules with no path are * by default.


This rule is important because it allows all file permissions not overridden elsewhere in the AppArmor profile – including execute permissions. To implement process whitelisting with AppArmor profiles we will have to change this rule because it’s presence is what allows execute permissions by default.

This was the first part of a two part series on process whitelisting in Kubernetes using AppArmor.
In the next part we will update the default AppArmor profile to implement binary whitelisting and review the advantages and limitations of using AppArmor to implement Kubernetes process whitelisting.




About the author

Natan profile

Natan Yellin

Senior Software Engineer

Natan Yellin is a senior software engineer at and specializes in tools for securing Kubernetes Linux clusters. He is passionate about building firewalls and low-level security solutions.
Natan is also the proud owner of a blog about low-level Linux at, and in his personal life, he enjoys cooking and gardening.

Subscribe for updates, fresh insights, stories and tips

The latest posts delivered to your inbox