我翻译的一篇Docker的白皮书 - 容器安全简介
容器安全简介
Docker白皮书
译者:李毅中国惠普大学资深培训专家
摘要
最近几年中软件开发方式的演进已经根本性地改变了应用程序。这些改变影响了对于底层基础架构、工具以及流程(管理整个生命周期)的需求。应用程序 从大型单体代码库转变成了一种由很多小型服务松散耦合而成的集合,人们称之为微架构。在一种渴望的驱使下-用一种在基础架构间可以移植的新方式来更快地交 付更多软件,我们看到身边越来越多的敏捷组织从中收益,这些组织囊括了初创企业和大型企业。
这些新的应用程序不仅行为不同而且他们的架构从根本上改变了它们是如何随着时间的推移进行构建、部署、管理及安全防护的。不再需要在虚拟机 (VM)或者裸机上以配置大型服务器来处理少量的大型负载,而代之以在一组普通硬件之上运行小型应用程序集。通过在应用程序之间共享同一个OS,容器升格 为这些新应用程序的打包模型。较少的OS实例在主机资源、成本和持续运维等方面为应用程序基础架构带来了明显的优势。
为了增强一个系统的弹性,关于应用程序安全的最佳实践长久以来都建议分层的策略。在这篇论文中我们将介绍与Linux技术及Docker容器有关的安全概念。
要点包括:
·容器通过减少主机自身的暴露区域以及对应用程序与主机之间、应用程序之间进行隔离实现了更多一层的防护,而这种隔离并没有使用更多的底层基础架构资源。
·容器和虚拟机(VMs)可以部署在一起,从而为应用程序服务提供更多的隔离及安全层级
·容器的性质有利于快速、便捷的应用程序打补丁以及OS更新,应用程序及基础架构的分层,有助于维持整体的安全合规性
Docker概述
Docker是一个用于构建、分发及运行分布式应用程序的开发平台。组织应用Docker是为了简化并加速他们的应用开发和部署。Docker可 以很容易地把分布式应用程序组合成轻量级的应用程序容器,它可以动态地调整而不会中断应用程序并且可以顺场地在开发、测试和生产环境中移植,而这些环境则 是运行在一个数据中心或者不同云服务提供者的物理机或虚拟机上。
该平台的核心是Docker Engine,一个轻量级的应用程序运行环境,它也提供了强大的工具来构建、分发和运行Docker应用程序容器。Docker Engine可以安装到任何一个运行LinuxOS的物理机、虚拟机及便携电脑之上或者数据中心里、云服务提供者的服务器上。Docker的容器模型允许 多个隔离的应用程序容器运行在同一个服务器上,从而更好地使用硬件资源并且降低行为异常的应用程序对于其他应用程序及物理主机的影响。Docker容器是 基于应用程序的映像而创建的,而这些映像是由一个称之为Docker Hub的注册机(registry)负责存储、管理与发布。在Docker Hub上有对Docker用户开放且来自社区和生态系统的公共、私有及官方映像仓库。
Docker Engine使用客户端-服务器架构。一个Docker客户端与Docker Engine的守护进程通信,该守护进程负责为一个特定的应用程序服务完成构建、分发和运行Docker容器的所有繁重工作。Docker客户端可以是运 行的一个命令行工具或者通过DockerAPI集成到第三方应用程序中。客户端和守护进程可以运行在相同的系统中,但是客户端也可以远程地访问 DockerEngines。所有客户端与守护进程之间的通讯可以使用TLS进行防护并且借助RESTfulAPI来实现。Docker是使用Go语言开 发的,守护进程使用多个库和内核功能来实现它的设计目标。
Linux技术最佳实践及Docker的缺省安全
容器技术以两种方式提升了应用程序的安全性。首先通过使用应用程序之间和应用程序与主机之间的隔离层来实现。第二,它通过限制对主机的访问来降低 主机的暴露区域来保护主机以及其上的容器。Docker容器构建在Linux的最佳实践之上,从而提供了更强的缺省配置和未来能够降低风险的可配置设置。
最佳实践对于Linux系统管理员的建议包括应用最少权限原则。系统管理员长久以来都被要求使用chroot流程并且为部署的应用程序创建资源限 制。Docker容器模型通过在他们自己的根(root)文件系统中运行应用程序、允许使用独立的用户账号、以及更进一步地使用Linux名字空间和 cgroups为程序提供沙盒来强制资源限制从而支持并强化了这些限制。这些强大的隔离机制在Linux内核中已经存在几年了,Docker将其发扬光大 并且将分布式的应用程序视为独立、隔离的单元从而极大地简化了相关约束的创建和管理。
Docker利用一种叫做命名空间(namespace)的Linux技术来提供隔离的工作空间,我们称之为容器(container)。当一个容器被部署时,Docker为该特定的容器创建一套命名空间,将它与所有其他正在运行的程序隔离开。
Docker也利用了Linux的控制组。控制组(Control group或者缩写为cgroup)是内核级的功能,它允许Docker控制每一个容器访问的资源从而保障容器的多租户应用。控制组使得Docker能够 共享可用的硬件资源,而且如果需要可能够为容器设置限制和约束。一个典型的例子是对某个特定容器可用内存的总量进行限制,这样它就不会消耗掉整个主机的资 源。
进程限制
限制访问和能力将降低暴露区域在攻击面前的潜在弱点。Docke的缺省设置被设计为限制Linux的capabilities(能力)。 Linux的传统视角是以root权限对比用户权限的方式考虑OS安全,而现在的Linux已经演进到支持一种更加细致的权限模 型:Capabilities。
Linux capabilities支持用户capabilit及传统方式的颗粒度规格,root用户可以访问每一个capability。通常非root用户有一 个更加严格的capability集,但是一般通过使用sudo或执行文件的setuid权限为他们提供了提升至root级别访问的选择。这会构成一个安 全凤风险。
在一个Docker容器内部的缺省capability集不到一个Linux进程所被授予的capability集的一半(见 LinuxCapabilities图)。这降低了通过应用程序漏洞提升为root用户而拥有一切权利的的风险。Docker应用了一个额外的颗粒度等 级,它对传统的root/非root二分法进行了极大的扩充。在多数情况下,应用程序容器不需要root用户所拥有的全部能力,因为需要这些权限的大多数 任务都由容器之外的OS环境来处理。容器可以使用一套缩减的capability集运行,而这不会对应用程序带来负面的影响反而提升了系统整体的安全级别 并且缺省使得运行的应用程序更安全。它使得在入侵过程中很难发起系统级别的破坏,即使入侵者想要提升到root权限也无能为力因为容器的能力从根本上被限 制住了。
设备及文件限制
Docker通过使用设备资源控制组(cgroup)机制来封装应用程序并限制对主机上物理设备的访问,进而进一步地降低暴露区域。容器没有缺省的设备访问,需要明确地授予对设备的访问。这些对于正在运行程序的限制保护了容器主机的内核及其硬件,无论是物理的还是虚拟的。
Docker容器使用copy-on-write文件系统,它允许使用同一个文件系统映像作为多个容器的基础层。即使想同一个文件系统映像进行写操作时,容器察觉不到其他容器所作的变更,从而有效地隔离了运行在不同容器中的进程。
如果你销毁了一个容器,所有对容器的变更也会丢失,除非你提交了你的变更。提交变更作为一个新的层将追踪并审计对基础映像的变更,它可以作为在 DockerHub中存储的一个新映像进行发布而且可以在一个容器中运行。这个审计线索对于提供信息来于保持合规而言是很重要的。当一个容器被破解或者发 现漏洞,它也能够快速且方便地回滚到以前的版本。为了程序的运行,只有很少的几个核心Linux内核文件系统不得不用在容器环境中。大多数这些强制性的文 件,诸如/sys和其他/proc下的文件,是以只读的方式进行挂载。这进一步限制了可能对它们进行写操作的访问能力,即使是有权限的容器进程也是如此。
应用程序映像(Image)安全
Docker允许容器映像来源于硬盘或者来自一个远程的注册机。DockerHub是一个SaaS注册机,它包含公共映像和大量Docker用户 可以公开搜索和下载的官方映像仓库。官方仓库是由独立软件开发商(ISV)和Canonical、Oracle、RedHat等众多Docker贡献者认 证的仓库。这些映像由这些上游伙伴维护和支持以确保映像是最近的。Docker并不知道当前使用的是哪一个远程的注册机,这允许企业使用任何本地注册机、 基于公有云的这册及或者DockerHub的组合方案。
对于健全的安全措施而言合适的应用程序映像工具是非常关键的。无论计划内还是计划外,IT管理员需要快速且方便地执行应用程序更新并且让这些变更 也部署到相关的应用程序上。Docker容器的易于组合的特性和动态性使其能够适应持续的变更而几乎不会中断应用程序的其余组成部分。
由于容器映像是持续变更的而且需要通过你的基础架构推送和拉取,安全通信对于构架和发布应用程序而言就非常重要。所有与注册机的通信都使用 TLS,只为保证双方的私密性及内容的完整性。缺省情况下是强制使用公共PKI基础架构信任的凭证,但是Docker允许额外地把一个公司内部的CA根证 书加入信任库。
缺省之外:Docker增强的控制
Docker用户可以在缺省配置的基础进行扩展,进一步严格地对应用程序使用Linux能力或修改文件等访问进行限制。操作人员可以使用只读文件系统来部署容器,从而显著地限制在容器生成过程中通过隐性设备访问来欺诈系统的潜在风险。
通过“cap_drop”功能,也可以超越缺省值来限制Docker容器的capabilities。Docker也兼容于seccomp(安全 计算模式- Secure computing mode),Docker Engine源代码树的‘contrib“目录中的一个例子就展示了这种集成性。使用seccomp,甚至可以使得所选择的系统调用(syscalls) 对于容器进程完全禁用。
以上描述的配置控制是作为运行环境功能提供的,它专注于隔离、构建、调度和应用程序管理机制。这允许用户根据使用者的操作和组织需求为他们的容器调整和配置策略。
开源安全
Docker Engine是Docker项目中的一个开源项目,可以从这里获取: https://github.com/docker/docker 。作为一个开源项目,我们与社区密切配合来进行创新并解决他们提出的问题。发布的贡献指南中严格要求使用代码审查来确保在高质量代码的基础上进行工作。 Docker Inc.也以合同的方式把外部安全公司引入季度审计及(或)针对对我们的代码和基础架构进行的渗透测试。
Docker支持安全漏洞的责任披露并且允许安全研究人员提交潜在漏洞便于在线修复: https://www.docker.com/resources/security/
其他Linux内核安全功能
现代的Linux内核除了之前提到的capability、命名空间和cgroups等概念外,还有很多其他安全构件。Docker能够利用诸如 TOMOYO、AppArmor、SELinux和GRSEC等的现有系统,其中有些为Docker容器提供了安全模型模板。你可以使用这些访问控制机制 的任何一种来进一步定义定制化的策略。
Linux主机可以用很多其他方式进行加固而且部署Docker在增强了主机安全的同时却不会影响其他安全工具的使用。我们建议你在运行的 Linux内核中使用GRSEC和PAX。这些补丁集加入了很多内核级安全检查,使得在编译和运行环境中尝试破坏或者一些常见披露技术变得更加困难。这并 不是Docker专有的配置,但是可以在系统范围内应用并从中获益。
在基础架构中部署Docker
将容器与虚拟机结合
容器和虚拟机都能在一个共享主机上为运行的应用程序提供隔离环境,只是来自不同的技术视角而且可以基于应用程序环境的需要很好地独立使用或者结合在一起。
虚拟机使用一个完整的OS,包括它自己的内存管理和虚拟设备驱动程序。隔离是在虚拟机层面提供的,因为资源是为客户OS(guestOS)仿真而 来的,因此允许在单一主机上运行一个或多个并行(而且甚至是不同的)OS。虚拟机提供了应用程序进程和逻辑系统之间的边界。Hypervisor会拒绝虚 拟机执行可能会危害主机平台完整性的指令。对主机的保护有赖于提供一个安全的虚拟硬件环境来运行一个OS。这个架构对于主机资源利用率有不同的影响,但是 允许在单一主机上通过不同的OS运行应用程序。
Docker容器在相同主机上运行的所有应用程序容器之间共享一个单独的主机OS。隔离是由Docker Engine在每一个应用程序层面上提供的。使用容器降低了每个应用程序的开销因为避免了多个OS实例。这使得容器更加轻量、快速且易于扩展和收缩,并且 可以实现比完整的虚拟机更高的密度等级。这种方式只能对共享一个通用OS的应用程序有效,就像Linux用于分布式应用程序一样。
虚拟机的常规方式不允许他们能真正缩小到只运行一个单独应用程序服务的级别。一个虚拟机可以支持一个相对丰富的应用程序集,但是在单一虚拟机内运 行多个微服务而不使用容器则会带来问题因为对于有些组织而言每个虚拟机只运行一个微服务在经济上是不可行的。与虚拟机相结合地部署Docker容器能够实 现整个服务组中的服务彼此隔离而且运行在一个虚拟机中。这种方式通过引入两个层级:容器与虚拟机,而提升了分布式应用程序的安全。另外这种方式达成了更有 效的资源使用并且可以为所定义的隔离和安全目标在减少虚拟机数量的同时增加容器的密度。
因此可以通过把虚拟化和容器相结合所提供的隔离比单独使用虚拟化在成本和资源效率上更好。Docker容器与可以保护虚拟机自身的虚拟化技术能够完备搭配,并且为主机提供深度防御。
在裸机上运行Docker
容器在主机及其应用程序之间提供了一层保护,在应用程序和主机之间提供了隔离。相比于不使用任何虚拟化或者容器技术,这使得它在逻辑上部署应用程序会更加安全。借助容器,很多应用程序服务可以部署在单一主机上从而使得组织能够实现对其基础架构更好的利用率。
然而,裸机部署不能提供最底层的硬件隔离,故而它不能充分发挥Intel的VT-d和VT-x技术的优势。在这个情境下,对于主机隔离的等级而言容器不能完全替代虚拟化。
容器为运行在裸机之上的应用程序提供了隔离,它保护了主机去应对大量的威胁而且能够满足非常广泛的使用场景需求。在以下的场景中虚拟机可能不是最 好的选择而容器则可以取而代之;性能至上的应用程序运行在一个单租户的私有云中,跨租户或跨应用程序的攻击并不是一个值得关注的问题;或者他们正在使用不 能直接映射给虚拟机的专用硬件,或者该硬件提供直接内存访问而使得虚拟化的优势无法发挥。很多GPU运算的用户就面对着这个问题。
运行在裸机之上的Docker容器与他们运行在虚拟机上时拥有相同的高级别限制。无论那种场景,一个容器通常都被允许修改物理的或虚拟的设备。
生命周期管理
软件开发只是应用程序生命周期的一个阶段。测试、运行及管理阶段的安全需求是非常关键的,并且涉及了不同的团队、工具和流程。无论计划内或者计划 外的持续运维和更新都需要保持操作运行的安全和平稳。更新应用程序部件的过程往往不是小事儿甚至更严重,即使有补丁自动发布工具也会很繁琐。此时的问题是 安装的补丁是否影响了其他的东西?安装这个补丁有多难?如果更新失败要如何完全地回滚?构建映像的便利性应该延展到对这些映像的更新并且安装安全更新。运 维工程师可以利用映像标签来以一种自动的方式来安全地、容易地安装计划内的安全更新并为之前的版本安装更新。计划外的补丁和修复程序也可以通过提交、更新 和重新发布容器映像的方式安装。更新的映像可以推送到Docker Hub或任何其他的注册机以便于同其他团队进行分享和发布。
Docker容器的这些特点使得系统管理员在更新系统工具、软件包甚至是主机的内核都很容易。OS的升级周期被明显地缩短而且也容易实现,显著地 降低了基础架构在攻击面前的总体暴露面。相比于虚拟化模型中每个主机有多个OS需要维护,Docker环境中每个主机只有一个OS需要维护。需要打补丁和 更新的OS实例数量减少将降低与安全合规相关的开销。
确保安全合规性等同于应用最新的更新并保持对系统包含什么及其变更历史进行跟踪。对生产环境中容器的变更历史能够进行审计可以验证对生产系统没有 进行有危害的变更,而且当问题出现时也有能力把容器回滚到一个已知的正常状态下。总之,使用分层手段使得参照公开常见风险和漏洞列表(CVE)来检查OS 包和应用程序依赖性变得更加容易。
总结
基于微服务的架构为应用程序在整个生命周期内如何开发、部署及管理提出了不同的需求而且打包工具的变化及安全模型也要能够支持它。安全需求可以采取分层的方式来满足,它以应用程序栈来对待整个基础架构而且通常会综合多种技术来保证满足每一层的安全需求等级。
Docker在组织使得深度防御概念的部署简单化了。使用Docker可以立即带来有益,不仅仅是在应用程序开发和部署的速度和便利性方面,也表 现在安全方面。通过隔离、约束及隐形地应用了大量的最佳实践–否则需要在组织内的每个OS上进行明确的配置,直接部署Docker自然就会提升系统的整体 安全等级。
总而言之,企业使用了Docker容器可以在不增加应用程序基础架构开销的前提下增强安全:
·容器通过在应用程序与主机之间以及在应用程序之间进行隔离而不需要使用更多的底层基础架构资源和降低主机的暴露区域来提供了更多一层的保护。
·容器和虚拟机可以部署在一起来为所选择的服务提供更多的隔离和安全层级
·容器的性质有利于快速、便捷的应用程序打补丁以及OS更新,应用程序及基础架构的分层,有助于维持整体的安全合规性