返回 登录
0

Docker的安全性

译文作者:晏东精灵云创始人,全栈工程师,曾任索贝数码及赛门铁克架构师,精通分布式系统开发。官网网址:https://www.ghostcloud.cn

写在前面

  这篇博客的作者Jerome Petazzoni是DotCloud的资深工程师,我会结合他的讲解,辅以一些个人的见解,从以下几个方面来阐述Docker的安全性问题。

  • 容器安全性的本质,结合namespace和cgroups来分析;
  • Docker守护进程如何受到攻击;
  • linux 内核自身的防攻击功能以及如何影响容器;

Kernel namespace

  Docker初期是基于LXC,后来逐渐过渡到libcontainer,所以容器和传统linux container使用的是同一种安全机制。当你启动一个容器的时候,背后实际调用的是lxc或libcontainer在启动容器。这个命令会创建一系列的namespace和control groups.(注:namespace是用来创建一系列隔离用的,比如pid, 网络,挂载点等;Control groups主要用来限定容器的CPU和内存)。

  那lxc和libcontainer到底有什么区别呢?lxc和libcontainer都是操作系统级的虚拟化实现技术,应该来说是Docker的核心,初期的版本Docker使用的是lxc,很多都不受其控制。后来Docker公司决定用Go来重写这一部分,不出意外的话 libcontainer会成为日后的默认linux conainer。不过不管是lxc还是libcontainer,其都是依赖于linux 的namespace 功能。Namespace提供了最直接的进程级的隔离。每一个容器拥有自己的网络栈,也就是说一个容器不能访问另一个容器的socket和网卡,当然相互之间是可以通过TCP/IP来进行访问的。 从网络架构来说,所有的容器都挂载到一个桥接之上。这就是说容器类似于一个物理的机器链接到了交换机之上。

  有时候我们会问,Namespace到底稳定成熟不?实际上从linux内核的2.6.15开始,就支持了Namespace,具体时间是2008年。而且这项功能也已经广泛运用在了生产环境中。Namespace实际是OpenVZ的替代品,OpenVZ是2005年Release的。因此,Namespace无论是在设计上,还是在实现上都是非常稳定的。

Control Groups

  Control Groups是另一个linux容器的关键组件。它主要实现容器资源的限定,比如内存,CPU, Disk IO等等,有了这项功能,容器就不可能耗尽某一项系统资源。 因此,通过合理的配置,可以有效的防御注入DDOS攻击。特别是当你的应用运行在PaaS或IaaS上时,必须防范资源的过渡消耗。而CGroup是2006年就发布了,并被合并到了linux内核的2.6.24版本中。

对Docker 守护进程的攻击

  要在系统上运行容器,就必须运行Docker守护进程。以前Docker的守护进程是必须以root权限来运行的,不过现在已经可以使用非root运行了。因此如果说Docker可能存在安全隐患的话,还不如说是Docker守护进程有安全隐患。

  对于Docker的守护进程,只能是特定用户可以控制。Docker本身是可以将主机上的任何文件系统共享给容器使用的,因此在使用卷挂载功能时,一定不能将根目录或容器所在目录共享给容器使用。看似这个是有隐患,但实际上任何一个虚拟化系统都是允许文件系统共享的,只是做了一定的限定而已,对于 Docker来说,只是放开了而已,只要你不共享根目录,就跟传统的Hyper-V虚拟化是相同的。如果你容器内使用了宿主的文件系统,然后对外提供对外服务,就需要特别注意。

  另一个可能有安全隐患的地方是Docker 守护进程可以监听到socket之上,这样就有可能在外网对Docker进行控制。针对这种情况,Docker提供了SSL机制,来进行防范。

  除此之外,容器内的运行用户如果为root,同时主机又共享了文件系统给容器,也会存在安全隐患。不过Namespace已经支持非root用户运行,所以作为一个最佳实践, 容器内应该尽量避免使用root运行,如果一定要使用,主机的文件系统也要特别小心。因此,Docker本身要做的其实就是两点:

  • 将容器的root用户映射为主机的非root用户

  • 允许守护进程以非root用户运行
      

  总之,如果你在服务器上运行Docker,最好只运行Docker,并将其他所有的服务移至容器内部。

Linux Kernel Capabilites

  默认情况下,Docker的容器中只启动了部分内核的功能,这意味着什么呢?

  所谓内核Capabilites,就是一些功能需要root或者非root用户才能执行的功能。比如,通常一个进程是不能用非root监听1024以下的网络端口。如果要打破这种限制需要设置net_bind_service的内核capability。除此之外,还有很多其他的内核capabilities,通常很多都是需要root权限。 而这一点对容器来说是非常重要的。但这又是为什么呢?

  你的很多应用程序都需要以root来运行,比如SSH, cron,syslogd等,硬件管理工具,内核模块的管理,网络配置等等。而容器则不同,很多任务都是在容器内完成的:

  • SSH访问可以单独运行在一个容器内

  • cron,可以以普通用户权限来运行

  • log,可以由第三方工具来维护

  • 硬件管理,你不需要在容器里面运行udevd或者相关的守护进程

  • 网络管理,容器内不应该使用这些命令

  因此,在大多数情况下,容器是不需要使用真实的root权限。也就是说,容器内相比于主机使用了更少的内核capabilities,比如:

  • 禁止所有 mount操作

  • 禁止访问原始socket,避免网络包欺骗

  • 禁止一些文件系统操作,比如创建设备,改变文件的owner,或者属性

  • 禁止加载模块

  这意味着,即使黑客闯入容器,获得了root权限,他能做的事情也不是很多,很难对外部系统或者其他容器造成影响。

他内核的安全功能

  Capability只是很多安全功能中的一项,除此之外还有类似于TOMOYO, AppArmor, SELinux,GRSEC等。用户可以根据自己的需求配置这些服务。

和VM比较

  普遍的观点是大家认为传统虚拟化(Xen, VMWare, KVM等)的安全性高于容器,因为他们提供了更底层的隔离,即操作系统级的隔离。一个容器 是可以调用主机的系统调用的,而虚拟机只能通过hypervisor来调用,因此受攻击的面就会缩小。

  但是VM被认为比容器更安全的真实原因是它们在产品环境中的大量使用,得到了验证。目前的公有云厂商基本都是在卖VM,只有少数的PaaS提供商在 卖容器。因为容器比VM更节约资源,更容易管理,你将会在未来几年看到很多提供容器服务的厂商。同时,容器的受工具面也会逐步缩小。

  如果内核的缺陷导致恶意代码的执行,将会跳出容器到主机上,但是对于VM来说,不会跳出虚拟机。到目前为止,还没有任何基于这方面的demo。 但是,这可能是一个未来受攻击的点。但这是不是意味着容器没有VM安全呢?我们并不这么认为。首先hypervisor并不是绝对没有缺陷的,其次一般 严重的内核缺陷,都会很快被解决。

  同时也有另外一面,如果出现了一个内核缺陷,你需要升级内核并重启系统。有些时候,你也必须升级内核,并更新VM镜像。对于容器来说,更新是非常 方便的,因为内核并不是容器的一部分,你只需要升级内核即可。总体来说,容器肯定会越来越安全,而且现在已经有大批应用部署在容器之上。

和其他容器系统对比

  • 基于LXC的系统:之前和docke使用的是相同的技术,但是从libcontainer开始,已经不再使用了。

  • 非LXC系统:比如OpenVZ,它是一个比LXC更老的容器系统,很多人认为它更安全,但是很多LXC的开发者就是OpenVZ的开发者,而且他们很多认为 LXC不过是OpenVZ的重新设计,并且OpenVZ现在早已日薄西山,终究会被LXC替代。

  • 非linux容器系统:很多系统是非常厉害的,比如Solaris Zones,但是据我们所知这个系统在linux下效率和稳定性都不是很高。还有FreeBSD jails 但是这些更多是应用在VPS中。这些系统并不比LXC安全多少,而且应用也没有linux下的应用广泛。

端口导出(译者加)

  Docker默认的网络是通过nat方式暴露出去的,通常一个应用程序只会暴露一个端口,比如apache只暴露80端口。相比于虚拟机来说,这种只暴露指定端口的方式,肯定是更安全,受攻击的面更小。当然虚拟机也可以根据iptable等来做设置,但是按照我的经验,其实很少有人去做。

总结

  Docker的容器默认情况下是非常安全的,如果你使用非root用户运行程序,就更安全。很多人认为VM更安全,但安全不安全很大程度取决于你如何使用, 毕竟真正要做一个安全级别很高的系统,需要配置的东西太多,从这个层面来讲,容器反而更安全,即使你使用root运行应用,受影响的也只是当前容器。

评论