使用最新的安全增强功能调整 Docker

还没有读者喜欢这篇文章。
Shipping containers stacked

维基共享资源

自从我写了关于 Docker 安全系列文章的前两篇 文章 已经有一段时间了。本文将更新 Docker 自那时以来添加的新功能,并介绍正在通过上游 Docker 合并过程的新功能。

调整 Capabilities

在之前的文章中,我介绍了基于 Linux Capabilities 的容器隔离。

Linux Capabilities 允许您将 root 权限分解为更小的权限组。目前,默认情况下,docker 容器仅获得以下 capabilities。

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 模式下运行,这将关闭所有安全功能。

在 docker-1.3 中,添加了 --cap-add 和 --cap-drop。现在,为了运行 ntpd 容器,您可以直接运行

docker run -d --cap-add SYS_TIME ntpd

这将仅将 SYS_TIME capability 添加到您的容器。

另一个例子是,如果您的容器没有更改任何进程的 UID/GID,您可以从您的容器中删除这些 capabilities,从而使其更安全。

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

或者您可以删除所有 capabilities 并添加一个回来。

docker run --cap-drop ALL --cap-add SYS_TIME ntpd /bin/sh

# pscap | grep 2382
5417 2382 root sh sys_time

调整 SELinux 标签

与 capabilities 类似,我们添加了动态调整 SELinux 标签的功能。

如果您看过 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)

# 此模板接口创建 docker_apache_t 类型作为
# 可以作为 docker 容器运行的类型。该模板
# 为域提供运行所需的最小权限。
virt_sandbox_domain_template(docker_apache)

# 我知道容器内的 apache 守护程序将需要
# 一些 capabilities 才能运行。幸运的是,我已经有了 Apache 的策略,我可以
# 查询 SELinux 以获取 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 } ;

# 这些是允许容器监听
# 网络上 Apache 端口所需的规则。

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 需要解析针对 DNS 服务器的名称
sysnet_dns_name_resolve(docker_apache_t)

# 许可域允许进程不被 SELinux 阻止
# 在开发和测试您的策略时,您可能希望
# 在许可模式下运行容器。
# 当您对策略充满信心时,您需要删除此规则。
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=host 让容器共享主机 pid 命名空间
--net=host 让容器共享主机 net 命名空间
--ipc=host 让容器共享主机 ipc 命名空间

请注意,由于与主机共享 PID 或 IPC 命名空间需要我们禁用 SELinux 分离才能使其工作。

docker run -ti --pid=host --net=host --ipc=host rhel7 /bin/sh

您可能想阅读文章 超级特权容器中关于此的更多信息。

User profile image.
Daniel Walsh 在计算机安全领域工作了近 30 年。Dan 于 2001 年 8 月加入 Red Hat。

2 条评论

根据我在 OpenVZ 方面的经验,您无法在容器内运行 NTP 进程,NTP 守护程序必须在硬件节点上运行。

这在 LXC 和 Docker 中有所不同吗?

这是一篇很棒的文章,最终在实践中展示了如何扩展默认的 Docker SELinux 策略。

我今天使用它来构建 Chrony / NTP 的镜像,我不得不发现,当启用 SELinux 时,提到的“--add-cap SYS_TIME”不幸的是不够的,因为我可以清楚地看到 AVC 消息告诉我该 capability 被拒绝。

然而,结合本指南和这里的这个:http://developerblog.redhat.com/2015/04/21/introducing-the-atomic-comma… 我能够打包一个镜像,该镜像的 SELinux 策略模块在“atomic install”运行时安装。

总的来说,我认为结合 Docker 和这些相对容易的 SELinux 模块增强功能,使用和自定义 SELinux 变得更加容易。它真的不像人们通常说的那样邪恶 :)

Creative Commons License本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.