AppArmor profile:
cat /etc/apparmor.d/test-deny-write
#include <tunables/global>
profile test-deny-write flags=(attach_disconnected) {
#include <abstractions/base>
file,
# Deny all file writes.
deny /** w,
}
Loaded:
sudo apparmor_parser --Complain test-deny-write
sudo aa-status
apparmor module is loaded.
38 profiles are loaded.
31 profiles are in enforce mode.
/snap/snapd/20290/usr/lib/snapd/snap-confine
/snap/snapd/20290/usr/lib/snapd/snap-confine//mount-namespace-capture-helper
/usr/bin/man
/usr/lib/NetworkManager/nm-dhcp-client.action
/usr/lib/NetworkManager/nm-dhcp-helper
/usr/lib/connman/scripts/dhclient-script
/usr/lib/snapd/snap-confine
/usr/lib/snapd/snap-confine//mount-namespace-capture-helper
/usr/sbin/chronyd
/usr/sbin/tcpdump
/{,usr/}sbin/dhclient
cri-containerd.apparmor.d
lsb_release
man_filter
man_groff
nvidia_modprobe
nvidia_modprobe//kmod
snap-update-ns.google-cloud-cli
snap-update-ns.lxd
snap.lxd.activate
snap.lxd.benchmark
snap.lxd.buginfo
snap.lxd.check-kernel
snap.lxd.daemon
snap.lxd.hook.configure
snap.lxd.hook.install
snap.lxd.hook.remove
snap.lxd.lxc
snap.lxd.lxc-to-lxd
snap.lxd.lxd
snap.lxd.migrate
7 profiles are in complain mode.
snap.google-cloud-cli.anthoscli
snap.google-cloud-cli.bq
snap.google-cloud-cli.docker-credential-gcloud
snap.google-cloud-cli.gcloud
snap.google-cloud-cli.gsutil
snap.google-cloud-cli.kubectl
test-deny-write
13 processes have profiles defined.
13 processes are in enforce mode.
/usr/sbin/chronyd (1376)
/usr/sbin/chronyd (1377)
/metrics-server (12860) cri-containerd.apparmor.d
/usr/bin/dumb-init (13041) cri-containerd.apparmor.d
/nginx-ingress-controller (13053) cri-containerd.apparmor.d
/manager (13086) cri-containerd.apparmor.d
/usr/local/nginx/sbin/nginx (13114) cri-containerd.apparmor.d
/manager (13136) cri-containerd.apparmor.d
/usr/local/nginx/sbin/nginx (13155) cri-containerd.apparmor.d
/usr/local/nginx/sbin/nginx (13156) cri-containerd.apparmor.d
/usr/local/nginx/sbin/nginx (13157) cri-containerd.apparmor.d
/manager (13250) cri-containerd.apparmor.d
/manager (13565) cri-containerd.apparmor.d
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
Pod definition:
cat n.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx
annotations:
container.apparmor.security.beta.kubernetes.io/nginx: localhost/test-deny-write
name: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
dnsPolicy: ClusterFirst
restartPolicy: Always
kubectl apply -f n.yaml
pod/nginx created
kubectl get pods
NAME READY STATUS RESTARTS AGE
...
nginx 0/1 CrashLoopBackOff 1 (3s ago) 7s
kubectl logs nginx
/docker-entrypoint.sh: 13: cannot create /dev/null: Permission denied
/docker-entrypoint.sh: No files found in /docker-entrypoint.d/, skipping configuration
2024/01/06 11:27:50 [emerg] 1#1: mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)
nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)
Now AppArmor works in enforce mode despite profile being loaded in complain mode. Only way to make it work as complain not enforce is to change the profile definition from deny to audit:
...
audit /** w,
...
Then reload the profile in --Complain
mode again. This makes the pod start and events are getting audited:
kubectl logs nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2024/01/06 11:36:57 [notice] 1#1: using the "epoll" event method
2024/01/06 11:36:57 [notice] 1#1: nginx/1.25.3
2024/01/06 11:36:57 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
2024/01/06 11:36:57 [notice] 1#1: OS: Linux 5.15.0-1047-gcp
2024/01/06 11:36:57 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2024/01/06 11:36:57 [notice] 1#1: start worker processes
2024/01/06 11:36:57 [notice] 1#1: start worker process 29
2024/01/06 11:36:57 [notice] 1#1: start worker process 30
kubectl exec -it nginx -- sh
# echo a > a.log
sudo dmesg
...
[ 1943.792266] audit: type=1400 audit(1704541508.355:101): apparmor="AUDIT" operation="open" profile="test-deny-write" name="/dev/tty" pid=16159 comm="sh" requested_mask="w" fsuid=0 ouid=0
[ 1950.228525] audit: type=1400 audit(1704541514.792:102): apparmor="AUDIT" operation="mknod" profile="test-deny-write" name="/a.log" pid=16159 comm="sh" requested_mask="c" fsuid=0 ouid=0
[ 1950.234413] audit: type=1400 audit(1704541514.800:103): apparmor="AUDIT" operation="open" profile="test-deny-write" name="/a.log" pid=16159 comm="sh" requested_mask="wc" fsuid=0 ouid=0
But this defeats the purpose of complain mode.
System details:
uname -a
Linux node-qf1h 5.15.0-1047-gcp #55~20.04.1-Ubuntu SMP Wed Nov 15 11:38:25 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
kubectl version
Client Version: v1.28.0
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.28.0
AppArmor docs is not very helpful here: https://gitlab.com/apparmor/apparmor/-/wikis/Complain-Mode
Complain mode
learning application behavior TODO
complain mode and deny rules
One some versions of apparmor broken .... TODO
Is this AppArmor bug or did I miss something?