【编者的话】作者通过对Docker的最新安全更新的深入分析与探索,总结了四条有关Docker安全更新的调整建议,包括调整能力、调整SELinux的标签、多级安全模式、调整命名空间。
自我发表前两篇有关Docker安全系列的文章之后,至今已有一段时间。本文更新了自那以后有关Docker的新增内容,并且介绍了全新功能,其中涵盖了与上游Docker的合并过程。
调整能力在前面的文章中,我介绍了基于Linux功能的容器分离。
借助Linux功能,你可以分离根用户权限,形成更小的特权群。目前,在默认情况下,Docker容器只拥有以下功能。
CHOWN, DAC_OVERRIDE, FSETID, FOWNER, MKNOD, NET_RAW,
SETGID, SETUID, SETFCAP, SETPCAP, NET_BIND_SERVICE,
SYS_CHROOT, KILL, AUDIT_WRITE
在某些情况下,你可能要调整此列表,例如,如果你正在构建一个运行ntpd 或crony 的容器,那么需要能够修改主机的系统时间。由于需要CAP_SYS_TIME ,该容器将无法运行。在Docker的旧版本中,容器必须在--privileged 模式下运行,该模式关闭了所有的安全策略。
在Docker1.3版本中添加了--cap-add 和--cap-drop 。现在为了运行ntpd 容器,你可以只需运行:
docker run -d --cap-add SYS_TIME ntpd
其中只将SYS_TIME功能添加到了你的容器中。
另如,如果你的容器没有更改UID/GID的任何进程,你可以从容器中删除这些功能,使其更加安全。
docker run --cap-drop SETUID --cap-drop SETGID --cap-drop FOWNER fedora /bin/sh
# pscap | grep 2912
5417 2912 root sh chown, dac_override, fsetid, kill, setpcap, net_bind_service, net_raw, sys_chroot, mknod, audit_write, setfcap
或者你可以删除所有的功能后,再进行一一添加。
docker run --cap-drop ALL --cap-add SYS_TIME ntpd /bin/sh
# pscap | grep 2382
5417 2382 root sh sys_time
调整SELinux的标签与调整功能相类似,我们已经新增了调整SELinux标签的能力。
如果你已经看过SELinux coloring book(译注:有关强制执行SELinux政策的文章,此文图文并茂,易于理解),那么你会了解,我们可以通过类型和MCS/MLS 级别分离进程。我们使用类型以保护主机免受容器的干扰。但是,我们也可以调节类型以控制允许进入和离开容器的网络端口。目前,我们都以svirt_net_lxc_t 运行所有的容器。这种类型允许监听并连接所有的网络端口。我们可以通过调整SELinux的类型标签,从而设定容器的安全性。
借助常规的SELinux和Apache httpd,在默认情况下,我们只允许Apache进程来监听Apache的端口(http_port_t)。
# sudo sepolicy network -t http_port_t
http_port_t: tcp: 80,81,443,488,8008,8009,8443,9000
我们也可以阻断所有传出端口的连接。这可以帮助我们锁定Apache进程,即便像ShellShock一样的黑客通过安全漏洞破坏了应用程序,我们仍可以阻止应用程序成为一个垃圾邮件僵尸,或者允许进程攻击其它系统。正如《加州旅馆》歌中唱道,“你可以随时入住,但你永远无法离开。”
然而,借助容器的情况下,如果你在一个容器内运行一个Apache服务器应用程序,该应用程序会遭受攻击,Apache进程能够通过网络连接到任何网络端口、成为垃圾邮件僵尸或者攻击其他主机/容器。
使用SELinux创建一个新的策略类型供容器运行,这相当容易。首先,你可以创建一个SELinux TE(类型强制执行)文件。
# cat > docker_apache.te << _EOF
policy_module(docker_apache,1.0)
# This template interface creates the docker_apache_t type as a
# type which can be run as a docker container. The template
# gives the domain the least privileges required to run.
virt_sandbox_domain_template(docker_apache)
# I know that the apache daemon within the container will require
# some capabilities to run. Luckily I already have policy for
# Apache and I can query SELinux for the capabilities.
# sesearch -AC -s httpd_t -c capability
allow docker_apache_t self: capability { chown dac_override kill setgid setuid net_bind_service sys_chroot sys_nice sys_tty_config } ;
# These are the rules required to allow the container to listen
# to Apache ports on the network.
allow docker_apache_t self:tcp_socket create_stream_socket_perms;
allow docker_apache_t self:udp_socket create_socket_perms;
corenet_tcp_bind_all_nodes(docker_apache_t)
corenet_tcp_bind_http_port(docker_apache_t)
corenet_udp_bind_all_nodes(docker_apache_t)
corenet_udp_bind_http_port(docker_apache_t)
# Apache needs to resolve names against a DNS server
sysnet_dns_name_resolve(docker_apache_t)
# Permissive domains allow processes to not be blocked by SELinux
# While developing and testing your policy you probably want to
# run the container in permissive mode.
# You want to remove this rule, when you are confident in the
# policy.
permissive docker_apache_t;
_EOF
# make -f /usr/share/selinux/devel/Makefile docker_apache.pp
# semodule -i docker_apache.pp
现在使用新类型运行容器:
docker run -d --security-opt type:docker_apache_t httpd
现在,该容器与正常容器相比,有着更为严格的SELinux安全性。注意,你可能会需要查看审计日志,以观察你的应用程序是否需要额外的SELinux准许规则。
你可以通过使用audit2allow命令来添加规则到现有.te文件,重新编译并安装如下规则。
grep docker_apache_t /var/log/audit/audit.log | audit2allow >> docker_apache.te
make -f /usr/share/selinux/devel/Makefile docker_apache.pp
semodule -i docker_apache.pp
多级安全模式目前,我们使用MCS 分离,从而确保容器不被其它容器干扰或交互,除非它是通过网络进行的连接。某些政府系统需要不同类型的MLS(多极安全)政策。借助MLS,你可以基于看到的数据级别来标记进程。 MLS说如果你的容器要处理绝密数据,那么它应该在绝密的地方运行。我们已经添加了Docker选项,允许管理员设置容器在特定级别运行,这些应该会满足MLS系统的需求。
docker run -d --security-opt label:level:TopSecret --security-opt label:type:docker_apache_t httpd
这个命令将确保开启Docker容器的两个交替类型与级别,并且可以阻止容器使用不是相同标签的数据。不过这方面尚未通过认证,但我们愿意帮助第三方为MLS用户构建解决方案。
调整命名空间在其他有关安全的对话中,我已经讨论了命名空间如何被看作是一种安全机制,因为其删除了一个进程查看系统(PID命名空间)上其他进程的能力。网络命名空间可以删除通过你的命名空间看到其他网络的能力。 IPC(内部进程间通信)命名空间具有阻断容器使用其它容器的IPC能力。
Docker现在已经放宽这些限制。您可以用容器来共享主机的命名空间:
--pid=主机让容器共享主机的PID命名空间 --net=主机让容器共享主机的主机空间 --ipc=主机让容器共享主机的IPC空间
需要注意的是,既然已与主机共享PID或IPC的命名空间,这就需要我们依序禁用SELinux分离,阻断其工作。
docker run -ti --pid=host --net=host --ipc=host rhel7 /bin/sh
你可能会在这篇文章中阅读到相关方面的额外信息Super Privileged Containers。
原文链接:Tuning Docker with the newest security enhancements (翻译:田浩浩 校对:李颖杰) |