I am trying to build a Docker image that will serve as a Python jailed sandbox. For that, I'd like to apply a certain AppArmor profile to my container. My problem is that I do not manage to apply the child "python" profile to the actual container.
Here is how to reproduce the issue: first, write a "docker-python-sandbox" AppArmor profile with the following contents:
#include <tunables/global>
profile docker-python-sandbox flags=(attach_disconnected,mediate_deleted) {
################# copy-pasted from apparmor.d/docker
#include <abstractions/base>
network,
capability,
file,
umount,
deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir)
# 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/[^k]** w, # deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel)
deny @{PROC}/sys/kernel/{?,??,[^s][^h][^m]**} w, # deny everything except shm* in /proc/sys/kernel/
deny @{PROC}/sysrq-trigger rwklx,
deny @{PROC}/mem rwklx,
deny @{PROC}/kmem 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/efi/efivars/** rwklx,
deny /sys/kernel/security/** rwklx,
# suppress ptrace denials when using 'docker ps' or using 'ps' inside a container
ptrace (trace,read) peer=docker-default,
################# end of copy-paste
# deny access to all
deny /tmp/forbidden-all w,
# create python child profile
/usr/bin/python cx,
profile /usr/bin/python {
deny /tmp/forbidden w,
}
}
The first part is copy-pasted from the boilerplate docker-default profile. In the second part, we deny write access to "/tmp/forbidden-all". In addition, we (attempt to) deny write access to "/tmp/forbidden" to the python executable.
Here's my attempt at applying this profile:
$ sudo apparmor_parser --replace ./docker-python-sandbox
$ docker run --rm -it --security-opt apparmor=docker-python-sandbox python:3.8 /usr/bin/python -c 'open("/tmp/forbidden", "w").write("h4cked"); print("managed to write to forbidden file"); open("/tmp/forbidden-all", "w").write("h4cked")'
managed to write to forbidden file
Traceback (most recent call last):
File "<string>", line 1, in <module>
IOError: [Errno 13] Permission denied: '/tmp/forbidden-all'
As we can see, we successfully prevented writing to "/tmp/forbidden-all", but failed at preventing Python access to "/tmp/forbidden".
On the host, I can successfully create a profile that applies both these restrictions. This leads me to think that child profiles are ignored by the Docker container. Is this conclusion correct? Is it by design? If not, is there a way to address this?