It is well known that in cloud-native environments, we can control application access to resources in the cluster through RBAC mechanisms, but these are not enough for production environments, where the host is still a security risk when applications have access to host resources (e.g. Linux privilege words, network access, file permissions). For this situation, the Linux kernel security module AppArmor supplements standard Linux user and group-based permissions to limit the application to a limited set of resources and also serves as a protection for the Pod from unwanted attacks.
On a system with AppArmor enabled, the container runs with the default permission configuration for the container, but of course, the application can use a custom configuration as well. This article describes how to use AppArmor in a container.
How to Use AppArmor
AppArmor is a Linux kernel security module that allows system administrators to use per-program configuration files to restrict the functionality of programs. The configuration file can allow network access, raw socket access, and permission to read, write, or execute files on matching paths, among other features.
However, not all systems support AppArmor. by default, several distributions support the module, such as Ubuntu and SUSE, and many more offer optional support. You can check if the module is AppArmor-enabled by using the following command.
AppArmor operates in the following two types of profile modes.
- enforce: In enforce mode, the system starts enforcing the rule and reports the violation attempt in syslog or auditd (only if auditd is installed) and disallows the action.
- complain: In complain mode, the system does not enforce any rules. It only logs the offending attempt.
Configuration files are text files located in the /etc/apparmor.d/
directory. These files are named after the full path of the executable they are parsing, but replace /
with .
. For example, if the tcpdump
command is located in /usr/sbin/tcpdump
, the equivalent AppArmor configuration file would be named usr.sbin.tcpdump
.
You can also set up your own profile, such as the sample
profile to restrict write access to all files to.
Make the above configuration take effect.
AppArmor supports three main rules for Capability, File, and Network.
- Capability: Capability for Linux processes, where no Capability is granted, only a valid mask for the process capability set. e.g.,
capability sys_admin,
means that system administration tasks are allowed. - File:
- Read, write, execute, etc. permissions for files. For example,
/home/** rw,
means read/write access to all files under/home
. - File system mount rules, including whether to have mount and unmount permissions, file system type, mount parameters, and mount path. For example,
mount options=ro /dev/foo,
which allows read-only mounts to the/dev/foo
path. - rules such as chmod, chown, setuid, etc.
- Read, write, execute, etc. permissions for files. For example,
- Network:
- Permissions for network sockets, including create, accept, bind, etc., and the type and address of the network, e.g.,
network tcp,
indicating support for all tcp-type network operations. - Rules for DBUS, IPC, Signals, etc.
- Permissions for network sockets, including create, accept, bind, etc., and the type and address of the network, e.g.,
AppArmor’s configuration files are defined in a very flexible manner, and more specific use can be found in the AppArmor documentation.
Using AppArmor in Containers
After configuring the AppArmor configuration file on the host, let’s look at how to use it in a container.
Docker as the engine
When the container engine is Docker, for comparison, first run a normal nginx container and create a test file.
Next, run a container with the AppArmor configuration file sample that uses the above restrictions on write access to all files, and create a test file.
We can see that the AppArmor configuration file prevents the create file operation.
Engine is Containerd
When the container engine is Containerd, do the same test.
Use the sample configuration file in the container.
Similarly, the AppArmor configuration file prevents file creation operations.
Using AppArmor in Kubernetes
How do you use it in Kubernetes? The key is container.apparmor.security.beta.kubernetes.io/<container_name>
and the value has 3 different values.
- runtime/default: use the default container runtime configuration (e.g. docker-default).
localhost/<profile_name>
: uses the configuration file in effect on the node, with<profile_name>
as the filename.- unconfined: does not use any AppArmor configuration files.
Take the configuration file sample
created above as an example.
Also test if the pod has permission to create files.
Summary
In systems with AppArmor enabled, it is essential to use AppArmor to protect nodes and pods, but AppArmor configuration can be tricky. However, there are mature solutions in the community, such as the tool bane for quickly generating AppArmor configuration files, and DaemonSet for configuring the same configuration file for each node, see the example. You can also use node initialization scripts (e.g. Salt, Ansible, etc.) or images. You can also copy the configuration files to each node and load them via SSH, see the example.