我正在尝试构建一个 Docker 映像,该映像将用作 Python 监禁沙箱。为此,我想将某个 AppArmor 配置文件应用于我的容器。我的问题是我无法将子“python”配置文件应用于实际容器。
以下是重现该问题的方法:首先,编写一个“docker-python-sandbox”AppArmor 配置文件,其内容如下:
#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,
}
}
第一部分是从样板docker-default配置文件中复制粘贴的。在第二部分,我们拒绝对“/tmp/forbidden-all”的写访问。此外,我们(试图)拒绝对 python 可执行文件的“/tmp/forbidden”的写访问。
这是我应用此配置文件的尝试:
$ 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'
正如我们所见,我们成功地阻止了写入“/tmp/forbidden-all”,但未能阻止 Python 访问“/tmp/forbidden”。
在主机上,我可以成功创建应用这两个限制的配置文件。这让我认为 Docker 容器忽略了子配置文件。这个结论正确吗?是设计使然吗?如果没有,有没有办法解决这个问题?