概述

在多数情况下,启动Docker容器时都以root用户权限在运行,那么如果有ROOT权限可以做什么呢?当然可以做很多的事情,比如:访问所有信息、修改任何内容、关闭机器、结束进程以及安装各种软件等。

容器的安全性问题的根源在于容器和宿主机共享内核,如果容器里的应用导致Linux内核崩溃,那么整个系统可能都会崩溃。与虚拟机是不同的,虚拟机并没有与主机共享内核,虚拟机崩溃一般不会导致宿主机崩溃。

Docker的安全性主要体现在如下几个方面:

  • Docker容器安全性,如:是否会危害到宿主机或其他容器;
  • 镜像的安全性,如:如何确保下载的镜像是可信的、未被篡改过的;
  • Docker守护进程安全性,如:如何确保发送给Daemon的命令是由可信用户发起的。

接下来会通过一些简单的操作来验证一些安全问题,同时会提出一些安全上的实践和原则。

Docker访问主机系统

  • 首先来验证一下,能否访问主机上的存储密码相关的 /etc/shadow 文件?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    $ cat /etc/shadow # 使用普通用户访问
    cat: /etc/shadow: Permission denied
    $ who am i; groups; # 查看当前的用户和组
    vagrant pts/0 (10.0.2.2)
    vagrant docker
    $ sudo cat /etc/shadow # 使用管理员用户访问
    root:$6$HmunRCSU$YXNgf...bnj2AVtjAFfmh0:16744:0:99999:7:::
    daemon:*:16744:0:99999:7:::
    vagrant:$6$55jH0QFsuLa...vGb8lH/9jQy4r0:16744:0:99999:7:::
    ...
  • 再来验证一下,能否在 Docker 容器中访问/etc/shadow文件呢?

    1
    2
    3
    4
    5
    $ docker run -v /:/hostfs busybox cat /hostfs/etc/shadow
    root:$6$HmunRCSU$YXNgf...bnj2AVtjAFfmh0:16744:0:99999:7:::
    daemon:*:16744:0:99999:7:::
    vagrant:$6$55jH0QFsuLa...vGb8lH/9jQy4r0:16744:0:99999:7:::
    ...

    可以看到,在容器中是可以访问宿主机上只有root用户才能访问的密码敏感文件的,当然也是可以访问其他root权限的文件的。

  • 再来看一下,能否在Docker容器中修改主机文件系统?

    1
    2
    3
    4
    5
    6
    $ ls / | grep threat
    $ docker run -it -v /:/hostfs busybox touch /hostfs/threat-on-the-way
    $ ls / | grep threatls / | grep threat
    threat-on-the-way

    可以看到,在 Docker 容器中,能够在宿主机根目录创建文件,并且可以修改主机文件系统。更严重的时,如果是 Privileged 容器,即在运行容器时指定--privileged=true参数,则能够允许容器所有设备执行任意操作,能够读写内核内存/proc/kcore,使用参数--net=host可以嗅探主机所有网络流量。

  • 最后,来查看一下 Docker 容器和Metadata存储在哪儿?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    $ ls /var/lib/docker
    aufs containers graph linkgraph.db network repositories-aufs tmp trust volumes
    $ cd /var/lib/docker/; sudo du --max-depth=1
    4 ./trust
    88 ./network
    5246812 ./aufs
    4 ./tmp
    579872 ./volumes
    1900 ./containers
    11740 ./graph
    5840444 .

    运行态容器默认都是使用/var/docker/lib目录,容器内部写日志、产生运行时数据等都会影响该目录,并且产生的文件越来越多,占用空间越来越大,因此需要定期清理无用的镜像和容器,应为Docker挂载点/var/docker/lib创建单独的分区,最好是SSD盘。
    另外,最推荐使用供应商最支持的存储驱动程序,aufs是唯一的允许容器共享执行文件的存储驱动,但可能会导致严重的内核崩溃。

Docker安全最佳实践

为了保证 Docker 安全性,需要在各方面遵循一些实践和原则,包括宿主机方面、Docker守护进程、使用镜像以及容器运行方面。

在宿主机方面

  • 保持内核及时更新,防止黑客利用未修复的漏洞进行攻击
  • 增强主机安全保护,如果主机不安全了,容器也就谈不上安全了
  • 保持Docker及时更新,特别要关注Docker安全相关方面的更新

守护进程方面

  • 只允许受信用户控制Docker守护进程,保证与Daemon的连接是可信的
  • 不使用不受信的镜像仓库,因为镜像可能会被篡改过
  • 必要时请为Docker守护进程应用 TLS 认证网络
  • 限制容器之间的网络通信,如果两个容器之间没有通信的必要就限制其网络通信功能

使用镜像方面

  • 在Dockerfile中为容器创建一个非root用户,具体方法可以参阅 文章
  • 以非root用户运行容器进程,最大程度控制用户的权限范围
  • 只使用受信的基础镜像,可由最小基础镜像开始(Busybox, Alpine),最好是建立本地仓库镜像
  • 仅安装必要的包,因为可能有些包会有漏洞,一定程度上降低风险
  • 重新构建镜像时需要包含安全补丁,防止黑客利用漏洞实施攻击

容器运行时方面

  • 不要到产品环境中使用任何开发者工具(boot2docker, kinematic)
  • 限制容器使用Linux内核能力和资源使用,为守护进程设置受限的控制资源权限(–ulimit)
  • 不要使用 Privileged 容器,如果使用--privileged参数将授予容器与主机几乎相同的权限
  • 指定容器重启策略为on-failure,重启策略有四种,详细可以参阅 Restart policies
  • 使用强制权限控制系统 AppArmorLinux安全增强工具 SELinux 保证额外的安全层

小结

Docker安全性主要体现在容器安全性、镜像安全性和守护进程安全性,可以看到在Docker容器中能够访问宿主机的高权限资源,如果管理和使用不得当,将造成严重的后果,因此,在平时使用Docker时应在多方面遵循一些最佳实践和原则,包括宿主机方面、Docker守护进程、使用镜像以及容器运行等方面,尽可能保证 Docker 安全性。

特此声明: 本文大部分内容译自内部培训资料


References