docker的全面安全防护需要考虑docker的生命周期各个阶段的保护,本文介绍了实际应用环境中docker的安全防护。
Docker作为应用容器中最引人瞩目的实现方式,在近几年得到飞速的发展,大有成为应用容器事实标准的趋势,国内外不少企业已经将其应用到生产系统中了,有理由相信随着docker自身技术的完善和相关技术生态的建立,将成为下一代云计算的基石。
Docker的优点很多,由于其诞生的目的就是便于持续的集成和快速部署,尽量减少中间环节,这也为其安全控制带来难度, Gartner在确定2017年中最高安全技术,关于容器安全是其中一项,原文如下:
Containers use a shared operating system (OS) model. Anattack on a vulnerability in the host OS could lead to a compromise of allcontainers. Containers are not inherently unsecure, but they are being deployedin an unsecure manner by developers, with little or no involvement fromsecurity teams and little guidance from security architects. Traditionalnetwork and host-based security solutions are blind to containers. Containersecurity solutions protect the entire life cycle of containers from creationinto production and most of the container security solutions providepreproduction scanning combined with runtime monitoring and protection.
报告分析了容器安全面临的挑战:容器使用共享操作系统(OS)模型。对主机操作系统中的漏洞的攻击可能导致所有容器被攻击,且容器本身并不完全安全。但真正的问题在于由开发人员以不安全的方式部署,安全团队很少或根本没有参与,安全架构师也没有指导。
Docker 容器安全吗? {#contenttxt}
本身这个问题就是一个哲学问题,答案是否定的-不安全,因为没有绝对安全。其实对docker容器安全质疑最大的一点就是其隔离的彻底性,与其对比就是当前成熟的虚拟机(VM)技术。相对于VM,docker容器只是对进程和文件进行虚拟化,而VM做到了OS级别的虚拟化。从这个角度看VM的隔离性确实要好于docker容器,也就是说对宿主机的安全影响VM要远远小于docker,但换个角度看,这也恰恰正是docker的一个优点:轻量级,高效以及易移植。所以,安全和易用永远存在在一个平衡点,本文探讨的前提是认同docker带来的便利性,也接受其带来的安全风险,而要做的是利用一些的安全手段来将其风险降到可接受范围。
而容器安全如何来实现呢?
其实在Gartner的报告中也提到了,需要对docker全生命周期的安全防护,信息安全本质上就是控制风险,如果从一个docker的生命中周期面临的安全威胁来设计docker的安全防护策略,那安全控制的思路就会十分清晰。
首先,来简单捋一下docker容器的生命周期,一个docker容器从产生到运行部署大致分为如下三个状态:
- --Dockerfile:用于创建image镜像的模板文件,出于管理和安全的考虑,docker官方建议所有的镜像文件应该由dockerfile来创建,而当前不少用户把docker当虚拟机来使用,甚至容器中安装SSH,从安全的角度,这是不恰当的。
- --Image:镜像文件,对比PC端的概念,我们可以把它理解为服务器端的可执行软件包。一旦打包生成,如存在安全问题,那这些问题也被一并打包,最后导致安全事件。
- --Container:运行起来的image文件就是容器了,从外来看就是一个应用,可对外提供服务了。
所以不难发现,docker容器的生命周期,就是一个镜像文件从产生、运行到停止的过程,对其安全防护的目标就很明确了,那就是:
接下来,我们把docker容器生命周期和实际工作中结合起来,大致如下图所示:
在一般企业内,一个标准的产品发布流程大致如下:研发人员将代码提交给代码库;QA和安全人员通过jekins等工具进行编译并测试;测试完成后,由运维人员获取最终上线版本,发布到生产环境。也可能是测试完成后,直接发布到生产环境。
化繁为简,可将docker生命周期拆为两个大阶段,非生产环境阶段和生产环境阶段,这两个阶段安全控制的目标如下:非生产环境中保证镜像安全可信,生产环境中保证镜像正确的运行。
两个阶段安全保护措施
Docker公司与美国互联网安全中心(CIS)合作,制定了docker的最佳安全实践,其中包括了主机安全配置、docker守护进程配置、docker守护程序配置文件、容器镜像和构建、容器运行安全、docker安全操作六大项,99个控制点。几乎覆盖了docker安全要求各个方面,我们也对其进行了翻译和整理,在本专栏的后续文章中会陆续发布。
保证非生产环境中的镜像安全
-- 容器使用非root用户运行
为了防止容器逃逸而获得宿主机的权限,容器内应用以非root用户身份运行,如果用户已经在容器镜像中定义,则默认情况下容器将作为该用户运行,且不需要特定的用户命名空间重新映射。可以在Dockerfile中添加用户:RUN useradd -d / home /username -m -s / bin / bash username USER username
--使用安全的基础镜像
如果基础镜像存在安全问题,那整个镜像文件的安全性也无从谈起,用户可根据自身需求定制基础镜像,并强制要求组织内使用认可的基础镜像;也可使用第三方安全的镜像,这里推荐使用Alpine-linux,docker所有的官方镜像都使用其作为基础镜像,docker也会对其维护更新,所以安全性有保证。
--删除镜像中的setuid和setgid权限
setuid和setgid权限可用于提权。虽然有时候必须要使用到,但如果被滥用,可能会导致非法的提升权限。可以在镜像中限制这些权限的使用。具体做法可参考:在构建镜像时通过在Dockerfile中添加以下命令来删除这些权限,一般在Dockerfile的末尾添加:RUN find / -perm +6000-type f-exec chmod a-s {} \;|| true
--启用Docker的内容信任
内容信任允许当用户使用远程Docker仓库进行操作时,以执行镜像标记的客户端签名和验证。内容信任提供了对从Docker仓库发送和接收的数据使用数字签名的能力。这些签名允许客户端验证特定镜像标签的完整性。
在默认情况下,内容信任是禁用的。可通过如下命令进行启动: export DOCKER_CONTENT_TRUST = 1
--最小安装原则:
安全的普适法则,不要安装任何与应用无关的东西。
--对镜像进行安全漏洞扫描
镜像中包含了很多的插件及软件包,需要对这些软件包进行漏洞扫描,并根据结果安装补丁或更新软件,Coreos提供了一款开源docker镜像安全扫描器-Clair,(github地址:https://github.com/coreos/clair)。Clair可对镜像文件进行静态的安全扫描,并结合CVE给出漏洞扫描结果,运行效果如下:
关于Clair的实现原理,会在后续的文章介绍,同时我们参考了Clair的实现方式,优化了开发了一款docker镜像扫描器,也会在适当的时候推出并开源。
如何保证生产环境中容器的安全?
- --对docker宿主机进行安全加固
务必保证docker宿主机的安全,需要对宿主机的系统进行安全加固处理,主机加固可以参考相关的安全checklist以及各企业制定的主机安全规范,在这里就不在赘述。
- --限制容器之间的网络流量
在默认情况下,同一主机上的所有容器之间网络流量不受限制。因此,每个容器都有可能在同一主机上的容器网络上读取所有数据包。这可能会导致意外泄露信息。因此,需要限制容器间通信具体操作:在守护进程模式下运行docker,并将'--icc = false'作为参数。如:/ usr / bin / dockerd --icc = false
- --配置Docker守护程序的TLS身份验证
在默认情况下,Docker守护程序绑定到非联网的Unix套接字,并以root权限运行。若将默认的docker守护程序更改为绑定到TCP端口或任何其他Unix套接字,那么任何有权访问该端口或套接字的人都可以完全访问Docker守护程序。因此,不应该将Docker守护程序绑定到另一个IP /端口或Unix套接字。如果必须通过网络套接字暴露Docker守护程序,需为守护程序和Docker Swarm API配置TLS身份验证。
- --启用用户命名空间支持
防止容器内的提权攻击的最佳方法是将容器的应用程序配置为无特权用户运行。对于必须使用roo身份运行的容器,可以将该用户重新映射到Docker主机上特定用户。映射的用户被分配一个范围的UID,它们在命名空间内作为正常的UID,但对主机本身没有特权。关于使用用户命名空间隔离容器在后续文章中详细介绍。
- --限制容器的内存使用量
在默认情况下,容器可以使用主机上的所有内存。可以使用内存限制机制来防止一个容器消耗所有主机资源的拒绝服务攻击,具体可使用使用"-m"或"--memory"参数运行容器。如下:
$> docker run <运行参数> --memory <memory-size> <Container ImageName或ID> <Command>
- --适当设置容器CPU优先级
在默认情况下,CPU时间在容器间平均分配,可使用CPU共享功能来设定优先级。 CPU共享允许将一个容器优先于另一个容器,并禁止较低优先级的容器频繁地占用CPU资源。这样可确保高优先级的容器更好地运行,且可以有效的防止资源耗尽攻击。
针对docker安全配置检查,docker官方提供了一个脚本工具docker-bench-secruity(github地址:https://github.com/docker/docker-bench-security),检查依据便是CIS的最佳安全实践,运行界面如下:
通过前文介绍,列举了在docker容器生命周期需要进行的安全控制措施,但如果仅靠人工实施和监督,可能效果不会太好。若能将docker各个生命周期的安全管理自动化才是最佳实现方式,docker安全刚刚开始呀:)