共计 4490 个字符,预计需要花费 12 分钟才能阅读完成。
我在 Opensource.com 上写这些有关 Docker 安全的东西,想阐述的就一点——“纸已经包不住火了(containers do not contain)”
Red Hat 和 Docker 其中一个主要的目标,就是确保这一陈述不是绝对正确的。我在 Red Hat 的小组仍在努力利用别的安全机制使 container 更加安全。这些少数的几个安全特色,我们目前正在攻克 ,他们 未来 可能成为影响 Docker 和 container的方式。
用户 namespace
用户 namespace 基于内核 namespace,可以更好地将主机和容器分离起来。
基本方法就是宿主机创建一系列的 UID,例如 60000-61000,然后映射到内部的 namespace 0-1000,也可以用 GID 实现。内核会把 docker 容器内的 UID 0 识别、鉴定为外部的 UID 60000,任何一个没有被映射过的进程或者 UID 在容器内部都会被识别为 UID=-1, 从而禁止他们访问容器,包括所有的镜像都不允许访问。如果你想使用有用户 namespace 认证的镜像,那么你就得切换到容器内部 root 用户的 UID 对应的外部 ID。另一个问题就是外部 UID 0 挂载进入容器的卷、硬盘等设备在容器内部是没有权限访问的。你必须用 `chown` 命令将 UID 切换成内部可以的 UID。
chown -R 60000:60000 /var/lib.content
用户 namespace 的另一个问题在于,你不许给不同的容器分配不同段的 UID 进行映射。如果你有成百上千个容器,那么如何宿主机分配映射的 UID 就是个问题。
用户 namespace 是一个很炫酷的事情,他们可以直接利用 namespace 的优势,如果把容器进行如上的操作,那么我们可以抛弃掉所有的宿主系统提供的功能。也就是说,当用户 namespace 生效后,我们可以完全不再需要宿主系统提供的功能。我们也不再需要 selinux 提供的安全标签的策略了。
使用案例
三个可以用到用户 namespace 的方案如下:
1. 只映射 UID=0。增加容器之间的隔离度,甚至可以完全抛弃 capabilities 机制。这样做无疑可以增强容器和宿主机之间的安全性,但是也不会相对地提升容器之间的隔离度。所以只需要假设所有 DOCKER 容器的 ROOT 的外部 UID 为 2,那么,外部的 UID= 2 映射到容器内部 UID=0,外部 GID= 2 映射到内部 GID=0,凡是大于 2 的全部映射到自己。这样能最大程度的减少从容器内部获取宿主机的 root 权限。当然这样也能减少挂载文件系统时遇到的麻烦。这样处理之后,内部 root 用户 mount 的磁盘,外部是无法读取,(也就不会有 SUID 这个问题)。同样,其余的关于用户的 namespace 的处理也是一样。
2.openshift 式的解决办法。每个容器都有自己单独的 UID/GID,如同每个用户都有自己的 UID 和 GID 一样。只有容器用得到内核 capabilities 时这样才有必要,用不到的时候意义不大。
3. 按照段来映射。每个容器都映射一个 UID 段,每个容器映射的 UID 段各不相同。但是复杂性会随着容器数目增加急剧增加。挂载文件系统可能会成为一个大问题。可以增加一个功能,当容器内部 mount 的时候便执行对应的 chown UID:GID /SRC 命令,这样一定程度上可以解决挂载的问题。
然而我不认为这三个解决方案可以叠加。我也看过对内核“加入容器时,重设 mount 目录的 UID 的提议”,甚至对乐死 mount –bind 的命令也执行重设 UID,但是我觉得这个提议交给那些写内核的人比较好,我也会继续参考那些做安全人的意见。
用户 namespace 已经并入 libcontainer 了,也已经打好了能这样让 docker 运行起来的补丁。
Seccomp
有个问题,那就是这里和别的地方提到的容器隔离措施全都是依赖与内河。空气和电脑接触,但是空气无法和电脑内核交流。但是容器就不一样,所有的容器都是直接和内核进行交换信息。如果宿主机有个漏洞,那么这个漏洞就击垮所有的安全措施,docker 容器也会变得无法控制。
X86_64 的 linux 内核有超过 600 个系统调用。只要其中其中有一个有漏洞,那么都可以导致容器的权限提升。因此有些系统调用是基本用不到的,所以应该禁止使用这些系统调用。禁止的越多越安全。
Seccomp 是 google 开发的禁止系统调用的沙盒类型的程序。例如 Chrome 的插件就得管管,毕竟插件都是来自互联网,没办法保证 100% 的安全。Google 在 Chrome 浏览器中使用 Seccomp 执行 chrome 插件确保系统的安全。
我的同事 Paul Moore,决定将 Seccomp 简化从而构建一个 C 库来管理系统调用库。现在他的成果 Libseccomp 也在 qemu,lxc,和 systemd 等软件中开始使用了。
我们也开始用 go 封装这个库然后再 libcontainer 中调用,进行过滤系统调用。
一般而言我们认为这些系统调用是可以禁止容器调用的:kexec_load, open_by_handle_at, init_module, finit_module, delete_module, iopl, ioperm, swapon, swapoff, sysfs, sysctl, adjtimex, clock_adjtime, lookup_dcookie, perf_event_open, fanotify_init, kcmp.
我们也在寻求其他可以禁止的系统调用,欢迎给提议。除此之外,我们考虑禁止调用许多旧的网络调用:Amateur Radio X.25 (3), IPX (4), Appletalk (5), Netrom (6), Bridge (7), ATM VPC (8), X.25 (9), Amateur Radio X.25 PLP (11), DECNet (12), NetBEUI (13), Security (14), PF_KEY key management API (15), 还有所有比 AF_NETLINK (16)需求的权限更多的系统调用。
加入系统调用过滤器的另一个方面就是可以过滤掉所有非本架构的调用,例如 X86-64 的电脑默认情况下是无法使用 32 位的系统接口的。我们希望这个方案被设置成为 seccomp 的默认选项。
禁止了其他架构的系统调用,我们可以简单地认为我们直接缩小了一半被内核提权、内核攻击的风险。
调整 seccomp
类似于系统 capabilities 和 selinux 标签,我们允许使用命令行自己决定自己需要使用 / 禁止那些系统调用:
`docker run -d –security-opt seccomp:allow:clock_adjtime ntpd`
这条命令将会允许容器内使用 clock_adjtime 调用,因为是 ntpd 服务,所以必须得用来调整时间。
同样,
`docker run -d –security-opt seccomp:deny:getcwd /bin/sh`
这条命令将会禁止容器内执行的 shell 查询当前自己所在的目录。RedHat 的 Matt Heon 有一个展示这个功能的短片。
视频地址:https://www.youtube.com/watch?feature=player_embedded&v=sw3NjVMMXz8
我们默认会禁止很多的系统调用,但是仍旧有很多很危险的系统调用没有被禁止。你可以全部禁止,然后慢慢地加入希望使用的系统调用。
`docker run -d –security-opt seccomp:deny:all –security-opt seccomp:allow:getcwd /bin/sh`
事实上,docker 中运行 sh 需要比 getcwd 更多的系统调用。被禁止掉的调用都会记录在 `/var/log/autit/audit.log`。如果 audit 没有运行的话,那么将会记录在 `/var/log/messages` 中。
未来的 docker
我们将会继续增强 docker 的安全功能。如果 linux 内核中出现新的安全功能,或者 linux 内核中有安全功能的改进,我们也会去尽量的利用这些功能,加固容器的安全性。
另一个方面是我们开始关注容器的管理。目前的管理方式是,如果你能有权限对 docker 的 socket 和端口发送数据的话,那么你就能对 docker 做任何事情。(译注:尤其是端口,docker remote api 这种东西目前完全是无法禁止的)很遗憾的是目前我们的解决办法只有禁止非 root 用户的 /run/docker.socket 接口的访问。我们也开始着手增加授权,这样管理员就能证明自己是管理员,而不是有权力访问接口的别的用户。我们也开始增加适当的管理记录的功能,将管理员对某些容器的是否是特权运行的情况记录到 syslog 或者 journalctl。除此之外,我们还可能增加基于角色的访问控制(RBAC),简单的来说,就是超级管理员控制其他的管理员。例如:
一星级管理员只允许开启、停止容器。
二星级管理员有权利新建非特权的容器。
三星级管理员有最大的权力运行所有的容器,并且赋予容器最大的权限。
结论
当这些安全措施实施之后,docker 容器会更大程度的让你的宿主机远离风险。我们的目标就是让纸也能包下火(the ability for containers to contain,呼应译文第一段)。
CentOS 6/ 7 系列安装 Docker http://www.linuxidc.com/Linux/2014-07/104768.htm
Docker 的搭建 Gitlab CI 全过程详解 http://www.linuxidc.com/Linux/2013-12/93537.htm
Docker 安装应用(CentOS 6.5_x64) http://www.linuxidc.com/Linux/2014-07/104595.htm
在 Docker 中使用 MySQL http://www.linuxidc.com/Linux/2014-01/95354.htm
在 Ubuntu Trusty 14.04 (LTS) (64-bit)安装 Docker http://www.linuxidc.com/Linux/2014-10/108184.htm
Docker 安装应用(CentOS 6.5_x64) http://www.linuxidc.com/Linux/2014-07/104595.htm
Ubuntu 14.04 安装 Docker http://www.linuxidc.com/linux/2014-08/105656.htm
阿里云 CentOS 6.5 模板上安装 Docker http://www.linuxidc.com/Linux/2014-11/109107.htm
Docker 的详细介绍:请点这里
Docker 的下载地址:请点这里
英文原文:Docker security in the future
本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-03/115433.htm