Day 5 — Getting started with AppArmor

Ref: https://en.wikipedia.org/wiki/AppArmor
# apt list --installed |grep -i AppArmorapparmor/bionic-updates,bionic-security,now 2.12-4ubuntu5.1 amd64 [installed]
apparmor-profiles/bionic-updates,bionic-updates,bionic-security,bionic-security,now 2.12-4ubuntu5.1 all [installed]
apparmor-utils/bionic-updates,bionic-security,now 2.12-4ubuntu5.1 amd64 [installed]
libapparmor1/bionic-updates,bionic-security,now 2.12-4ubuntu5.1 amd64 [installed]
  • Install it using the below command
sudo apt install apparmor-profiles
  • To check if the AppArmor service is up and running.
# systemctl status apparmor
● apparmor.service - AppArmor initialization
Loaded: loaded (/lib/systemd/system/apparmor.service; enabled; vendor preset: enabled)
Active: active (exited) since Sun 2021-10-31 00:46:35 UTC; 18min ago
Docs: man:apparmor(7)
http://wiki.apparmor.net/
Main PID: 482 (code=exited, status=0/SUCCESS)
Tasks: 0 (limit: 2314)
CGroup: /system.slice/apparmor.service
  • The next step is to verify if the AppArmor module is enabled in all the nodes in the Kubernetes cluster. The value of Y means the AppArmor module is already loaded.
# cat /sys/module/apparmor/parameters/enabled 
Y
  • To apply AppArmor to your application, it’s applied as a profile. This profile must be loaded inside the kernel. As we can see, several profiles are already loaded in this host. These profiles are simple text files and define which an application can use resources.
# cat /sys/kernel/security/apparmor/profiles 
/usr/{sbin/traceroute,bin/traceroute.db} (complain)
/usr/sbin/smbldap-useradd (complain)
/usr/sbin/smbldap-useradd///etc/init.d/nscd (complain)
/usr/sbin/smbd (complain)
/usr/sbin/nscd (complain)
/usr/sbin/nmbd (complain)
/usr/sbin/mdnsd (complain)
/usr/sbin/identd (complain)
/usr/sbin/dovecot (complain)
/usr/sbin/dnsmasq (complain)
/usr/sbin/dnsmasq//libvirt_leaseshelper (complain)
/usr/sbin/avahi-daemon (complain)
/usr/lib/dovecot/ssl-params (complain)
/usr/lib/dovecot/pop3-login (complain)
/usr/lib/dovecot/pop3 (complain)
/usr/lib/dovecot/managesieve-login (complain)
/usr/lib/dovecot/managesieve (complain)
/usr/lib/dovecot/log (complain)
/usr/lib/dovecot/lmtp (complain)
/usr/lib/dovecot/imap-login (complain)
/usr/lib/dovecot/imap (complain)
/usr/lib/dovecot/dovecot-lda (complain)
/usr/lib/dovecot/dovecot-lda///usr/sbin/sendmail (complain)
/usr/lib/dovecot/dovecot-auth (complain)
/usr/lib/dovecot/dict (complain)
/usr/lib/dovecot/deliver (complain)
/usr/lib/dovecot/config (complain)
/usr/lib/dovecot/auth (complain)
/usr/lib/dovecot/anvil (complain)
/usr/lib/chromium-browser/chromium-browser (complain)
/usr/lib/chromium-browser/chromium-browser//xdgsettings (complain)
/usr/lib/chromium-browser/chromium-browser//sanitized_helper (enforce)
/usr/lib/chromium-browser/chromium-browser//lsb_release (complain)
/usr/lib/chromium-browser/chromium-browser//chromium_browser_sandbox (complain)
/usr/lib/chromium-browser/chromium-browser//browser_openjdk (enforce)
/usr/lib/chromium-browser/chromium-browser//browser_java (enforce)
syslogd (complain)
syslog-ng (complain)
klogd (complain)
ping (complain)
docker-default (enforce)
/usr/sbin/tcpdump (enforce)
/usr/lib/snapd/snap-confine (enforce)
/usr/lib/snapd/snap-confine//mount-namespace-capture-helper (enforce)
man_groff (enforce)
man_filter (enforce)
/usr/bin/man (enforce)
/usr/bin/lxc-start (enforce)
/usr/lib/connman/scripts/dhclient-script (enforce)
/usr/lib/NetworkManager/nm-dhcp-helper (enforce)
/usr/lib/NetworkManager/nm-dhcp-client.action (enforce)
/sbin/dhclient (enforce)
lxc-container-default-with-nesting (enforce)
lxc-container-default-with-mounting (enforce)
lxc-container-default-cgns (enforce)
lxc-container-default (enforce)
  • The simple Apparmor profile will look like this. What this profile is doing it’s denying all write access to the root filesystem.
#include <tunables/global>

profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
#include <abstractions/base>

file,

# Deny all file writes.
deny /** w,
}
  • To check which are the profile is loaded, you can use the aa-status command. As you can see, 56 profiles are already loaded, and 19 are loaded in enforce mode.
# aa-status 
apparmor module is loaded.
56 profiles are loaded.
19 profiles are in enforce mode.
/sbin/dhclient
/usr/bin/lxc-start
/usr/bin/man
/usr/lib/NetworkManager/nm-dhcp-client.action
/usr/lib/NetworkManager/nm-dhcp-helper
/usr/lib/chromium-browser/chromium-browser//browser_java
/usr/lib/chromium-browser/chromium-browser//browser_openjdk
/usr/lib/chromium-browser/chromium-browser//sanitized_helper
/usr/lib/connman/scripts/dhclient-script
/usr/lib/snapd/snap-confine
/usr/lib/snapd/snap-confine//mount-namespace-capture-helper
/usr/sbin/tcpdump
docker-default
lxc-container-default
lxc-container-default-cgns
lxc-container-default-with-mounting
lxc-container-default-with-nesting
man_filter
man_groff
37 profiles are in complain mode.
/usr/lib/chromium-browser/chromium-browser
/usr/lib/chromium-browser/chromium-browser//chromium_browser_sandbox
/usr/lib/chromium-browser/chromium-browser//lsb_release
/usr/lib/chromium-browser/chromium-browser//xdgsettings
/usr/lib/dovecot/anvil
/usr/lib/dovecot/auth
/usr/lib/dovecot/config
/usr/lib/dovecot/deliver
/usr/lib/dovecot/dict
/usr/lib/dovecot/dovecot-auth
/usr/lib/dovecot/dovecot-lda
/usr/lib/dovecot/dovecot-lda///usr/sbin/sendmail
/usr/lib/dovecot/imap
/usr/lib/dovecot/imap-login
/usr/lib/dovecot/lmtp
/usr/lib/dovecot/log
/usr/lib/dovecot/managesieve
/usr/lib/dovecot/managesieve-login
/usr/lib/dovecot/pop3
/usr/lib/dovecot/pop3-login
/usr/lib/dovecot/ssl-params
/usr/sbin/avahi-daemon
/usr/sbin/dnsmasq
/usr/sbin/dnsmasq//libvirt_leaseshelper
/usr/sbin/dovecot
/usr/sbin/identd
/usr/sbin/mdnsd
/usr/sbin/nmbd
/usr/sbin/nscd
/usr/sbin/smbd
/usr/sbin/smbldap-useradd
/usr/sbin/smbldap-useradd///etc/init.d/nscd
/usr/{sbin/traceroute,bin/traceroute.db}
klogd
ping
syslog-ng
syslogd
14 processes have profiles defined.
14 processes are in enforce mode.
docker-default (2300)
docker-default (2365)
docker-default (2371)
docker-default (2410)
docker-default (2497)
docker-default (2562)
docker-default (2653)
docker-default (2685)
docker-default (3412)
docker-default (3419)
docker-default (4481)
docker-default (4500)
docker-default (4687)
docker-default (4754)
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
  • These profiles can be loaded in three different modes
* enforce: AppArmor monitors and enforce the profile rules 
* complain: AppArmor will not enforce any profile rules but log the events
* unconfined: Nothing is enforced and it doesn't even log the events
  • To use AppArmor with pods. go to and create the file default deny file
cd /etc/apparmor.d
# cat default.deny
#include <tunables/global>
profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
#include <abstractions/base>
file,# Deny all file writes.
deny /** w,
}
  • To use AppArmor with Pod, you need to use the annotations whose format is key and value
  • Remember with annotations, you need to specify the container name, not the pod name
key: container.apparmor.security.beta.kubernetes.io/<container_name>
apiVersion: v1
kind: Pod
metadata:
name: hello-apparmor
annotations:
container.apparmor.security.beta.kubernetes.io/hello: localhost/k8s-apparmor-example-deny-write
spec:
containers:
- name: hello
image: busybox
command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
  • To load the profile
apparmor_parser -v default.deny 
Addition succeeded for "k8s-apparmor-example-deny-write".
  • Also, not the file name and the profile name is different. With annotation specify the profile name(k8s-apparmor-example-deny-write) not the file name(default.deny).
  • Create the pod
kubectl create -f /tmp/pod.yaml 
pod/hello-apparmor created
  • Verify the profile is loaded properly
# kubectl describe pod hello-apparmor |grep -i apparmor
Name: hello-apparmor
Annotations: container.apparmor.security.beta.kubernetes.io/hello: localhost/k8s-apparmor-example-deny-write
  • Test it. As you can see the file creation inside the / is denied
# kubectl exec -it hello-apparmor -- touch /tmp/test
touch: /tmp/test: Permission denied
command terminated with exit code 1

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Prashant Lakhera

Prashant Lakhera

AWS Community Builder, Ex-Redhat, Author, Blogger, YouTuber, RHCA, RHCDS, RHCE, Docker Certified,4XAWS, CCNA, MCP, Certified Jenkins, Terraform Certified, 1XGCP