Docker是基于Linux操作系统实现的应用虚拟化。
运行在容器内的进程,跟运行在本地系统的进程本质上并无区别,
配置不合适的安全策略将可能给本地系统带来安全风险,
因此,Docker的安全性在生产环境中是十分关键的衡量因素。
Docker容器的安全性很大程度上依赖于Linux系统本身,主要考虑下面几个方面:
(1)Linux内核的命名空间机制提供的容器隔离安全;
(2)Linux控制组机制对容器资源的控制能力安全;
(3)Linux内核的能力机制所带来的操作权限安全;
(4)Docker程序(特别是服务端)本身的抗攻击性;
(5)其它安全增强机制(包括AppArmor、SELinux等)对容器安全性的影响;
(6)通过第三方工具(如:Docker Bench)对Docker环境的安全性进行评估;
1.命名空间隔离的安全
Docker容器和LXC容器在实现上很相似,所提供的安全特性也基本一致。
当用docker run创建一个新的容器时,Docker将在后台为容器创建一个独立的命名空间。
命名空间提供了最基础的也是最直接的隔离,
在容器中运行的进程不会被运行在本地主机上的进程和其它容器通过正常程序发现和影响。
例如,通过命名空间机制,每个程序都有自己独有的网络栈,
意味着它们不能访问其他容器的套接字(socket)或接口。
当然,容器默认可以与本地主机的网络连通,如果主机系统上做了相应的交换设置,
容器可以像跟主机交互一样和其他容器交互。
启动容器时,指定公共端口或使用连接系统,容器就可以相互通信了。
从网络架构的角度来看,所有的容器实际上是通过本地主机的网桥接口docker0进行相互通信,
就像物理机器通过物理交换机通讯一样。
Linux内核从2.6.15版本(08年)开始引入命名空间,经历了数次的演化和改进。
与虚拟机相比,通过命名空间来实现的安全隔离并不是那么绝对。
运行在容器内的应用可以直接访问到系统内核和部分系统文件。
因此用户必须保证运行在容器内的应用是安全可信的,(这和直接运行在系统中的软件是一样的)
否则本地系统将可能受到威胁,所以必须保证镜像的来源和自身可靠。
Docker从1.13开始对镜像管理引入的签名系统,加强了对镜像安全性的防护,
用户可以通过签名来验证镜像的完成性和正确性。
2.控制组资源控制的安全
控制组时Linux容器机制中的另一个关键组建,它负责实现资源的审计和限制。
当使用docker run创建启动一个容器的时候,Docker将通过Linux的相关调用,
在后台为容器创建一个独立的控制组策略集合,该集合将限制容器内的应用对资源的消耗。
控制组提供了很多有用的特性,它确保了各个容器可以公平的分享主机的内存、CPU、磁盘IO等资源,
当然,更重要的是,通过控制组,可以限制容器对资源的占用,
确保了当某个容器对资源消耗过大时,不会影响到本机系统和其它容器的运行。
尽管控制组不负责隔离容器之间的相互访问、处理数据和进程,
但是它在防止而已攻击特别是服务器攻击(DDos)方面是十分有效的。
对于支持多用户的服务平台,特别是paas、容器云这类服务,控制组尤其重要。
3.内核能力机制
能力机制(Capability)是Linux内核一个强大的特性,可以提供细颗粒度的权限访问控制。
传统的Unix系统对进程权限只有根权限(root用户)和非根权限(非root用户)两种粒度的区别。
Linux内核从2.2版本其支持能力机制,它将权限分为更加细粒度的操作能力,既可以作用在进程上,也可以作用在文件上。
例如,一个Web服务器只需要绑定一个低于1024端口的权限,并不需要完整的root权限。
那么,它只需要被授权net_bind_service能力即可。此外,还有许多其它类似能力避免进程获取root权限。
默认情况下,Docker启动的容器默认只能使用一部分内核的功能。
使用能力机制对加强Docker容器的安全性有很多好处。
通常在服务器上需要运行一推需要特权权限的进程。
包括SSH、cron、syslogd、硬件管理工具模块、网络配置工具等,
容器跟这些进程是不相同的,因为几乎所有的特权进程几乎由容器以外的支持系统来进行管理。
例如:
ssh访问被宿主机上的ssh服务来管理;
cron通常应该作为用户进程来执行,权限交给使用它服务的应用来处理;
日志系统可以由Docker或第三方服务管理;
网络管理也在主机上设置,除非特殊需求,容器不需要对网络进行配置
大部分情况下,容器不需要真正的root权限,容器只需要少数的能力即可。
未来加强安全,容器可以禁用一些没必要的权限。包括:
禁止任何文件挂载操作;
禁止直接访问本地主机的套接字;
禁止访问一些文件系统的操作,比如创建新的设备、修改文件属性等;
禁止模块加载;
这样,就算攻击者获取了root权限,在容器中所作的操作也有限。
不恰当的分配了内核能力,会导致容器内应用获取破坏本地系统的权限。
默认情况下,Docker采用白名单机制,禁用了必须的一些能力之外的其它权限。
当然,用户也可以根据自身的需求启用额外的权限。
4.Docker服务端的防护
使用Docker容器的核心是Docker服务端。Docker服务的运行目前还需要root权限的支持,因此服务端的安全性十分重要。
首先,必须确保只有可信的用户才可以访问到Docker服务。
Docker允许用户在主机进而容器之间共享文件,同时不需要限制用户的访问权限,这就容易让容器突破资源限制。
例如,如果恶意用户启动容器的时候让主机的/目录映射到容器的目录下,那么容器就可以对主机的文件系统进行更改。
事实上,几乎所有的虚拟化系统都允许此类的文件共享,而没法阻止恶意用户将根文件系统挂载到虚拟机服务的事件。
这将会造成很严重的安全后果。因此,当提供容器创建服务时,要注意参数的安全检查。
为了加强对服务端的保护,Docker的REST API在0.5.2之后使用本地的Unix套接字替代原先绑定在127.0.0.1上的TCP套接字。
因为后者容器造成跨站脚本攻击,现在用户使用Unix权限检查来加强套接字的访问安全。
最近改进的Linux命名空间机制将可以实现使用非root用户来运行全功能的容器,
这将彻底解决共享文件系统所带来的安全问题。
目前Docker自身改进安全防护的目标是实现以下两个重要安全特性:
将容器的root用户映射到本地主机的非root用户,减轻容器和主机之间因权限提升而引起的安全问题。
允许Docker服务器在非root权限下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。
这些子进程将只允许在限定范围内进行操作。
5.第三方检测工具
(1)Docker Bench
Docker Bench是一个开源项目。
该项目按照互联网安全中心(Center for Internet Security,CIS)对于Docker 1.11+的安全规范进行的一系列环境检查,
发现当前Docker部署在配置、安全等方面的潜在问题。
CIS Docker规范在包括主机配置、Docker引擎、配置文件权限、镜像管理、容器运行时环境、安全项等六个方面进行了相关的约束和规定。
Docker Bench自身也提供了Docker镜像。
(2)clair
CoreOS团队推出的clair支持对容器的文件层进行扫面而发现潜在漏洞。