NIST IR 8176: 用于 Linux 应用容器部署的安全性担保要求

NIST 内部报告 8176

用于 Linux 应用容器部署的安全性担保要求

Ramaswamy Chandramouli 著

计算机安全分部,信息科技实验室

此出版物可从此处免费获得:

https://doi.org/10.6028/NIST.IR.8176

2017 年十月

美国商务部 秘书 Wilbur L. Ross, Jr.

美国国家标准技术研究所 NIST 主任和标准技术商务次长 Walter Copan

美国国家标准技术研究所内部报告 8176,37 页(2017 年十月)

此文档中可能会提到某些商业实体、设备或者器材以便充分地描述某种试验程序或者概念。这样的提名的本意并非暗示 NIST 对其的推荐或认可,也非暗示这些实体、器材或者设备一定是可用于该目的之最好的。

此文档中可能会有对于 NIST 的当前正在开发中的其他出版物的引用,以便符合其被赋予的法定责任。此出版物中的信息,包括概念和方法论,可以被联邦政府机构使用,即使是在这些附带的出版物完成之前。因此,直到每部出版物完成之前,当前的要求、指导意见和过程在其所存在之处仍然有效。关于计划和迁移的目的,联邦政府机构可能想要紧密跟踪由 NIST 提供的这些新出版物的进展。

我们鼓励组织机构在公开评论期间审阅所有出版物草案,并且向 NIST 提供反馈。除了上述出版物以外,NIST 的众多计算机安全出版物可以从 https://csrc.nist.gov/publications 获取。

关于此出版物的评论可以被提交至:

美国国家标准技术研究所

收件人:计算机安全分部,信息科技实验室,办事处大道 100 号(8930 邮递点),盖瑟斯堡,马里兰州 20899-8930

邮件:NISTIR8176@nist.gov

所有评论必须在美国信息自由法(FOIA)条款下发布。

计算机系统技术报告

位于美国国家标准技术研究所(NIST)的信息科技实验室(ITL)通过为国家的测定和标准基础设施提供技术领导来提升美国经济和公众福利。ITL 通过开发测试、测试方法、参考数据、概念实现的证明以及技术分析来推进信息科技的发展及其生产性的使用。ITL 的职责包括为联邦信息系统中的国家安全相关信息以外的成本高效的安全性和隐私性开发管理、行政、技术和物理方面的标准和指导意见。

摘要

应用容器正在企业 IT 基础设施中逐渐得到采用。已有安全性指导意见和反制措施被提议以解决与应用容器平台部署相关联的安全性问题。为了对基于这些建议而实施的安全性解决方案的有效性进行评估,有必要分析这些解决方案并且对它们为实现其预期目标所必须满足的安全性担保要求进行概述。这是此文档的贡献。关注的焦点是 Linux 平台上的应用容器。

关键字

应用容器;能力;Cgroups;容器镜像;容器注册表;内核可加载模块;Linux 内核;名称空间;可信平台模块

致谢

作者对 Serban Gavrila 的技术反馈和 Isabel van Wyk 的编辑审阅表示感谢。

受众

此文档的目标受众包括企业基础设施或者用于作为总体云服务的一部分而提供容器服务的基础设施中的容器栈的系统架构师和系统管理员。

商标信息

所有注册商标或者商标属于其对应的组织机构。

执行摘要

应用容器正在生产环境中逐渐得到采用,由于下列优势:较短的开发和部署周期,通过轻量级虚拟化而实现的资源效率,以及用于所涉及的过程的自动化的工具的可用性。与此同时,在部署过程中解决安全性问题对于企业而言同等重要。为了解决这些问题,NIST 已经通过 应用容器安全性指南Application Container Security Guide)(NIST 特别出版 800-190)一文(在此文档中被引用为 容器安全性指南)提出了安全性指导意见和反制措施。

容器安全性指南 一文标识出了针对托管容器的平台的组件以及在启动之前构建容器并且存储它们的过程所涉及的与之相关联的东西的安全性威胁。考虑到对于涉及容器的整个生态系统的总体性的安全性启示,此文档也提供了用于 6 种实体,以及通过它们实施的安全性反制措施,包括硬件、宿主操作系统(OS)、容器运行时、镜像、注册表和编排器。

为了以反制措施的形式实施这些建议,需要一种或者更多种安全性解决方案。为了使得这些安全性解决方案能够有效地实现其安全性目标,有必要分析这些安全性解决方案并且以安全性担保要求的形式详细列出它们所必须满足的度量标准。这是此文档的目标和贡献。

Linux 及其不同发行版构成了已部署的容器平台的宿主 OS 的主导组成部分。由于它们是开源产品,足够的安全性相关信息可用于分析那些可以利用 Linux 所提供的特性进行配置的安全性解决方案。因此,此文档关注的焦点是针对托管于 Linux 之上的应用容器的安全性解决方案的安全性担保要求。目标受众包括那些负责实际设计并且部署托管容器化的宿主的企业基础设施中的安全性解决方案的系统安全架构师和管理员。

第 1 章 简介

应用容器正在生产环境中逐渐得到采用,由于下列优势:较短的开发和部署周期,通过轻量级虚拟化而实现的资源效率,以及用于所涉及的过程的自动化的工具的可用性。为了解决这些环境中的安全性问题,应用容器安全性指南(美国国家标准技术研究所(NIST)特别出版 800-190)[1](在此文档的剩余部分中被引用为 容器安全性指南)一文标识出了针对托管容器的平台的组件以及在启动之前构建容器并且存储它们的过程所涉及的与之相关联的东西的安全性威胁。考虑到对于涉及容器的整个生态系统的总体性的安全性启示,容器安全性指南 一文也提供了用于 6 种实体,以及通过它们实施的安全性反制措施,包括硬件、宿主操作系统(OS)、容器运行时、镜像、注册表和编排器。

为了实施这些反制措施,需要一种或者更多种安全性解决方案。此文档讨论了能够提供反制措施所必需的功能的潜在的安全性解决方案,以及每一种安全性解决方案所应该满足的安全性担保要求的类型。这些安全性解决方案可以被宽泛地分类为:

  • (a) 用于提供启动过程完整性的基于硬件的可信根
  • (b) 使用宿主 OS 内核特性和内核可加载模块的配置选项
  • (c) 用于构建和存储容器镜像的保护措施
  • (d) 用于发布涉及多个容器和多个宿主的生产基础设施的编排器工具的配置选项

此文档的目的是在其被设计为去满足的安全性目标的上下文环境中检视每一种安全性解决方案,以及开发那些它们应该满足以使其有效的担保要求。被考虑的宿主 OS 是 Linux,由于以下原因:

  • (a) 其在容器栈中的广泛采用
  • (b) Linux 发行版是开源的,并且允许足够多的与安全相关的信息成为公共可用的

1.1 此文档的范围

容器技术栈的功能架构框图如图 1 所示。在此框图中,此栈由物理宿主(或者虚拟机(VM))、容器 OS(我们将会在此文档中将其引用为宿主 OS)、容器运行时,以及多个容器组成。此外,诸如下列任务全部由多种工具执行,并且被整合到编排器软件的整体控制之下:创建虚拟网络以便在容器宿主内部以及它们之间将容器连接起来(容器网络)、创建容器宿主集群(容器集群管理)、创建路径程序以便识别并且发现某个提供某种特定服务的特定容器(服务发现)、跨集群容器计划(容器计划),以及在不同容器内部计划特定的业务应用程序(应用程序计划)。在不同的容器宿主上将其作为容器实际启动起来之前,首先利用适当的开发工具创建一系列组件的模板,这些组件构成了一个称为容器镜像的容器。这些容器镜像被存储于容器注册表中(镜像管理)并且随后被推送至容器宿主并且利用容器运行时工具将其作为容器启动起来。容器运行时同时提供接口以用于配置宿主 OS 参数,以及与内核可加载模块相关联的设置以允许不同容器的安全部署。

图 1——容器技术栈

如图 1 所示,安全功能层跨越了容器技术栈的所有功能层。然而,覆盖了这些层的安全性解决方案必须通过下列组件来实现:

  • (a) 物理宿主(即硬件,由于托管于 VM 之上的容器超出了此文档的范围)
  • (b) 容器 OS(宿主 OS)接口
  • (c) 容器运行时接口
  • (d) 镜像管理和注册表接口
  • (e) 编排器接口

运行于容器栈中的容器可以是系统容器或者应用容器。其行为类似于完整的 OS 并且运行诸如 sshd(安全会话建立)以及 syslogd(日志能力)的程序的容器称为系统容器。而仅仅运行应用程序的容器称为应用容器 [2]。此文档专注于应用容器。在分析安全性解决方案以及它们所应该满足的担保要求之前,有必要叙述应用容器的执行模型以及假想的攻击模型。首先,应用程序在容器中作为单一的操作系统进程而运行。容器拥有应用程序代码本身以及软件栈(包括二进制文件和库)的副本 [3]。在大多数情况下,此栈可以利用某种类型的库系统组装起来,从而避免需要由开发者来从头构建和配置该栈。这种快速组装的栈在不同的容器产品供应中被赋予了不同的名称(例如建构包(buildpack)、墨囊(cartridge)等)。有一些栈被用于众多的流行编程语言运行时,诸如 Java、PHP、Node.js 和 Ruby 等。对于特殊的应用程序,开发者可以创建他们自己的自定义的栈。容器架构的部署模型可能涉及在独立的容器中并行运行相同应用程序的副本,甚至是跨越不同的容器的宿主。在此场景中,基础设施可能拥有某种机制以利用某种形式的负载均衡将传入的请求分布至同一应用程序的所有实例。

此处假想的攻击模型是,容器中的应用程序代码的漏洞或者错误配置(例如此容器被配置为运行于高权限模式)已经被攻击者利用。这将会允许攻击者获得对于容器运行时以及宿主 OS 内核中的高权限代码的控制权并且对其进行攻击,在此,后者被容器中的应用程序代码信任以提供诸如进程隔离等一些保护担保 [4]。此类攻击的一个范例是重放、录制、修改和丢弃某个网络包或者文件系统访问。此文档中讨论的安全性解决方案的本意是防止对于容器运行时和宿主 OS 的此类攻击。关于解决应用程序代码本身的内在不安全特性,诸如编程 bug、设计瑕疵或者执行模型等的解决方案超出了此文档的范围。

1.2 文档结构

此文档的剩余部分被组织进下列章节和附录中:

  • 第 2 章提供了关于不同的 Linux 内核特性(名称空间、控制组(Cgroups)、能力(Capabilities))以及内核可加载模块在为容器化的栈提供安全性中的功能的概述
  • 第 3 章描述了用于容器环境的基于硬件的安全性解决方案
  • 第 4 章概述了宿主 OS 保护措施以及与之相关联的担保要求
  • 第 5 章详细呈现了若干种容器运行时配置解决方案,用以为下列事物提供容器隔离:进程、文件系统、进程间通信(IPC)以及网络。本章还呈现了关于限制资源以及保证最小化权限的解决方案。所有解决方案都得到了分析,并且还呈现了一组必须被满足的担保要求
  • 第 6 章定义了用于构建和维护容器镜像的担保要求
  • 第 7 章简要讨论了用于容器注册表保护的担保要求
  • 第 8 章概述了用于编排器工具的基本安全性担保要求
  • 第 9 章标识了某些安全性解决方案的某些不理想的副作用,以及在使用这些解决方案时需要加以注意的事项
  • 第 10 章总结了此文档所覆盖的不同的安全性解决方案领域
  • 附录 A 提供了此文档中所使用的首字母缩略词的定义,以及
  • 附录 B 包含参考文献的列表

第 2 章 用于 Linux 应用容器栈的安全性解决方案

在 1.1 节中,宿主 OS(在此上下文环境中为 Linux)的接口被列出为用于为容器栈实现安全性解决方案的机制。有两种类型的接口:Linux 内核接口和内核可加载模块(又称为 Linux 安全模块或者 LSM)接口。与前一类接口相关联的 Linux 内核特性包括:名称空间、Cgroups 和能力。其中,名称空间和 Cgroups 的内核特性为运行在宿主 OS 上的进程提供隔离,并且可以成为开发容器概念的驱动特性。Linux 内核特性和内核可加载模块特性中的重要功能将会在后续章节中简要描述,以便为后续章节中所分析的安全性配置和解决方案提供上下文环境。

2.1 Linux 内核特性——名称空间

名称空间将与内核全局资源相关联的标识符表和其他结构分割到独立的例程之中。因此,它们将文件系统、进程、用户、网络栈、进程间通信(IPC)对象、主机名以及其他组件分割为独立的片断。例如,每一个文件系统名称空间都拥有其自身的 root 目录以及挂载表 [2]。这些不同的名称空间可以在随后以任何频率或者组合方式捆绑起来,以便对每一个容器的资源以及随后对它们的可访问性提供统一的视图。对于容器中的某个进程的资源的限制性的视图可以被延伸到某个子进程。诸如重映射的 root 文件系统和虚拟网络设备等的配置能力属于可以利用名称空间特性而启用的安全性解决方案的一部分。对于基于名称空间的安全性解决方案的担保依赖强制实施名称空间隔离的方法,而这进一步依赖与实施了适当的访问控制的每一个名称空间相关联的那一类元数据。

名称空间概念已经扩展到通用架构以用于隔离一系列内核全局资源,而这些资源之前的范围是面向整个系统的。因此,与之相关联的 API 也已经扩展到包括若干系统调用。然而,仍然有一些资源对于名称空间并不敏感(例如设备)。

2.2 Linux 内核特性——Cgroups

控制组(Cgroups)是一种内核机制,用于为某一个或者某一组进程指定并且强制实施硬件资源限制和访问控制,其目标是防止某一个进程消耗所有可用资源并且使得宿主上的其他进程和容器没有资源可用。因此,Cgroups 在一组进程之中进行隔离并且限制一定的资源以实现对于性能或者安全性的控制。受到控制的资源包括中央处理器(CPU)份额、随机访问存储器(RAM)、网络带宽以及硬盘 I/O [5]。它也可以被用于任务控制。

由 Cgroups 提供的安全性保护包括:

  • (a) 防止拒绝服务攻击:它可以提供针对拒绝服务攻击的保护以防止出现诸如失控容器等情况,通过利用下列特性,诸如通过 SIGSTOP 进行任务冻结、利用 PID Cgroup 设置进程 ID 的上限以限制每个用户的最大进程数量,以及指定诸如缓冲限制以及流量优先级级别(由 iptables 强制实施)等网络控制参数
  • (b) 设备完整性保护:它可以通过利用基于标签的访问控制或者利用允许指定设备白名单的特性来限制对设备的访问

对 Cgroups 的配置通过挂载某个类似于 /proc 或者 /sys 的特殊 Cgroup 虚拟文件系统来启用,该文件系统允许查看名称空间和控制的状态。此机制的漏洞在于,诸如卸载或者重复挂载等攻击可能使得由 Cgroups 配置设置的资源限制失效。Cgroups 可以在容器管理框架外部进行配置和管理,由于它是完全与宿主 OS 的内核相关联的配置特性。

2.3 Linux 内核特性——能力(Capabilities)

Linux 内核中的能力特性可以帮助分割可用于 root 的广泛的权限集合,以使得进程(在此文档的上下文环境中指容器)刚好被分配给执行某个特定功能所需的权限。在引入能力特性之前,需要打开网络套接字的进程必须以 root 运行以执行这一个功能。这意味着对应的二进制文件,诸如 /bin/ping 中的一个 bug 即可能允许攻击者获得该系统上的所有 root 权限 [6]。通过启用能力 CAP_NET_RAW,某个版本的 ping 可以被创建为仅拥有由此能力所启用的权限,而非完整的 root 权限。其安全性结果是,潜在的攻击者通过利用 ping 工具的漏洞所能获得的权限显著减少。

2.4 内核可加载模块(或者称为 Linux 安全模块或者 LSM)

内核可加载模块,如同其名称所提示的那样,是加载至 Linux 内核的模块,它们提供安全功能以增强那些由名称空间、Cgroups 和能力所提供的安全功能。其范例包括 SELinux、AppArmor 和 Seccomp。SELinux 通过对进程和对象应用分类来提供对于对象访问的控制,而 AppArmor 通过对进程应用配置文件来执行相同的功能。Seccomp 允许系统调用限制规范,并且因此减少 Linux 内核的攻击面。

2.5 应用容器安全性配置过程

Linux 宿主 OS 内核特性——诸如名称空间、Cgroups 和能力——可以被撬动以便为每一个容器创建一个安全配置。众多容器运行时产品提供 API 以便为宿主内的容器创建安全配置。一种典型的容器运行时,通常是通过客户端访问的,包含直接进行系统调用的库,该库以其客户端的名义执行诸如创建所必需的内核名称空间、Cgroups 和能力管理等任务。其他管理功能可能拥有安全性启示(例如由于不均衡负载而导致缺乏可用性),诸如在宿主之间分布容器以及创建宿主集群等,可以通过一组称为编排器的工具进行管理。

第 3 章 基于硬件的容器安全性解决方案

容器安全性指南 一文在其 硬件反制措施 标题之下推荐了一种始于测定/安全启动、提供经过验证的系统平台,并且构建一条植根于硬件中的信任链的可信计算模型。此信任链随后被延伸至引导程序、OS 内核,以及 OS 组件以允许对启动机制、系统镜像、容器运行时以及容器镜像进行密码学验证。为容器化的宿主实现可信平台模块(TPM)的技术解决方案在文献 [7] 中概述。此文档中将会讨论两种这样的方式,以及每一种解决方案所要求的安全性担保。

两种方式都涉及基于硬件的,或者物理的 TPM 和基于软件的 vTPM(虚拟 TPM)的组合。两种方式之间的差别在于 vTPM 在容器栈中所处的位置。3.1 节讨论了将 vTPM 置于 Linux 内核中的安全性解决方案,而 3.2 节讨论了将 vTPM 置于专用容器中的解决方案。

构建 TPM 架构并非为容器栈提供植根于硬件的信任的唯一一类方式。另一类已经被提议的方式是撬动某些 CPU 架构中的可信执行支持以保护运行于容器中的进程,防止来自同一容器栈中的来源的攻击。这包括同一栈中的高权限软件,诸如容器运行时和 OS 宿主内核 [8]。3.3 节讨论并且分析了一种基于此类方式的机制或者安全性解决方案。

3.1 宿主 OS 内核中的 vTPM——安全性担保要求

在文献 [7] 所提议的一种架构方式中,称为 vTPM(虚拟 TPM)的基于软件的模块置于 OS 内核中。为了使得此模块可用于多个容器,它需要被虚拟化。这是利用某个能够提供任意数量的基于软件的 vTPM 的内核模块而实现的,这些 vTPM 通过通常的机制暴露给容器,并且对容器用户空间呈现一个字符设备类型接口。此功能可以被实现为使得容器运行时(或者容器管理器)请求宿主 OS 内核创建一个新的 vTPM 并且将该虚拟设备指认给某个容器。这些 vTPM 被连接到托管容器栈的硬件平台中实现的 TPM(称为“物理 TPM”)。此架构方式的示意图如图 2 所示。

图 2——实现于内核模块中的 vTPM

上文讨论的架构方式的安全性担保要求可以在下列场景中检视:

宿主 OS 完全可信:宿主 OS 中的信任可以通过利用基于硬件的,或者物理 TPM 从硬件中延伸可信根来建立。由于宿主 OS 对于防止来自容器和进程的非授权访问而言是可信的,它对于防止对于内核中的 vTPM 的非授权访问也是可信的。更进一步地,存在这样的担保,即容器不能通过加载新的模块或者利用内核中的漏洞来修改宿主内核。因此容器可以被可靠地证明为处于它们自身的状态,通过利用 vTPM 的散列值延伸特性。

宿主 OS 不完全可信,并且在 vTPM 上需要独立的信任:为了在 vTPM 上实现信任,与建立硬件 TPM(物理 TPM)信任使用相同机制的方案在文献 [7] 中引用。在物理 TPM 中,硬件平台提供商签名一个签注密钥(EK)以证明 TPM 可信。这在随后被延伸,通过赋予每个 vTPM 实例其自身的签注密钥并且部署利用基于硬件的 TPM 来签名 vTPM 的签注密钥的协议。

3.2 专用容器中的 vTPM——安全性担保要求

拥有与 3.1 节所述的相同功能的基于软件的 vTPM 被构建起来,并且托管于某个专用容器(称为 vTPM 管理容器)中。此架构方式的示意图如图 3 所示。此 vTPM 拥有两大主要特性:

  • (a) 对基于硬件的(物理)TPM 的访问
  • (b) 通过某种通讯信道将 vTPM 接口暴露给其他容器,此信道可以是本地 UNIX 域套接字或者其他 IPC 机制。如果 IPC 机制被使用,则使用 vTPM 服务的容器需要额外的软件(在图 3 中称为“适配器”),该软件将 IPC 接口呈现为标准字符设备。在托管 vTPM 的容器中,一个守护进程将会处理来自其他容器的请求,而非上一案例中的内核模块

图 3——位于专用容器中的 vTPM

由此架构方式提供的安全性担保与容器栈中的宿主 OS 所提供的相同。宿主 OS,诸如 Linux,通过名称空间特性为属于不同容器的进程提供隔离。如果此功能工作正确,没有属于不同容器的进程可以访问部署于专用容器中的 vTPM 的状态。换言之,这种实现的安全性只会在发生容器逃逸攻击时受到破坏。并且,此方式提供的保护少于 3.1 节所述的方式(宿主内核中的 vTPM),由于内核可以更加可靠地限制其暴露给用户空间的访问。

3.3 撬动硬件的可信执行支持

Intel 于 2015 年为其 CPU 发布了 Software Guard eXtensions(SGX)[8],它提供了硬件机制,利用安全 enclave 的概念以保护用户层级的软件以防止高权限的系统软件的影响。enclave 页缓存(EPC)是一块受保护的物理内存区域,驻留于其中的应用程序代码和数据受到 CPU 访问控制的保护。如果 EPC 页中的代码和数据被移至 DRAM,它们立即被芯片上的内存加密引擎(MEE)加密,并且在它们被从 DRAM 中传输至 EPC 页时被解密。enclave 内存本身的完整性也是受到能够检测内存修改和回滚的机制保护的。因此,enclave 是由 SGX 为驻留于容器中的应用程序提供的可信执行环境。此技术可能于 2018 年中期可用。

第 4 章 对于宿主 OS 保护的担保要求

4.1 对于通用宿主 OS 保护的要求

安装容器专用 OS(相对于通用 OS 发行版而言),保持 OS 版本最新并且安装补丁,利用能够跟踪对 OS 的匿名访问的日志特性,以及任何授权以执行高权限操作,以上这些构成了 容器安全指南 一文中的宿主 OS 反制措施的关键。除了以上这些反制措施以外,在宿主上禁用所有未使用的接口(串行或者私有接口)并且最小化用户和管理员帐户和组也是良好的 OS 安全实践。除此之外,还有诸如 grsecurity [9] 和 PaX [10] 等 Linux 专用补丁可用于 Linux 发行版。所有措施组合起来应该为宿主 OS 提供下列安全性担保:

  • (a) 防止通过修改内存来操纵程序执行(例如缓冲区溢出攻击)
  • (b) 防止对现存的程序代码进行重新路由的企图(例如通用库中的系统调用)

4.2 针对容器逃逸的宿主 OS 保护的担保要求

宿主 OS 应该被保护起来以化解源自容器逃逸或者突破的威胁,并且所有容器都应该被保护起来以防止来自宿主上的其他容器的影响。有众多解决方案可用于 Linux 环境以启用这些保护,但是,此文档中所分析的 3 种解决方案是 SELinux、AppArmor 和 Seccomp,所有这些都利用内核可加载模块(利用首字母缩略词 LKM 或者 Linux 内核模块来引用)。SELinux,或者安全增强式 Linux 可以为进程和对象(例如文件、套接字)指认分类并且基于特定的分类组合指定访问限制。例如,一个具体的 SELinux 标签可以被应用于某个容器以强制实施某种安全策略(例如,托管网络服务器的容器仅可打开 80 或者 443 端口) [6]。AppArmor 是另一款 LKM 产品,它通过对进程应用能够限制其在 Linux 能力以及文件访问层级上所拥有的权限的配置文件来帮助实施强制访问控制。因此,这些控制是以数据为中心的,并且与 SELinux 相比,位于较粗的粒度等级。SECure COMPuting(Seccomp)是一个可以定义并且强制实施某种访问控制方法的模块,该方法允许指定容器中的某个应用程序可用于同内核进行交互的系统调用的数量。限制系统调用提供了一种限制执行环境,并且因此减小了内核的攻击面。对于某个进程的系统调用的允许的列表(即白名单)和禁止的列表(即黑名单)通过利用系统调用过滤器进行设置 [11]。

上述内核可加载模块或者 LKM 的总体目标是在 Linux 中提供的标准文件层级访问控制(自主访问控制或者 DAC)的基础上为进程和用户的访问权限提供一个额外层级的安全检查 [6]。这一目标因此得出以下需要被满足的安全性担保要求:

  • (a) 被授权在容器中运行应用程序的用户不应该被允许访问上述内核可加载模块
  • (b) 如果使用 SELinux,用于标记文件及其上级文件夹的 chcon 工具应该被应用于文件系统层级结构中的正确层级,以使得这将会保证最小化权限
  • (c) 如果使用 Seccomp,系统调用白名单(可被允许的调用列表)和系统调用黑名单(被禁止的调用列表)都应该被生成。容器的白名单中的系统调用的选择应该基于容器中托管的应用程序类型、部署状况以及容器大小。黑名单中包括的系统调用被用于高风险、可能易受攻击、未知地危险,以及被显式地禁止的系统调用 [11]。此类中的范例包括允许加载内核模块、重启、引发挂载操作以及其他管理调用的系统调用
  • (d) seccomp 实现使用 Berkley 包过滤系统(BPF),并且因此其完整安装通常称为 seccomp-bpf。seccomp-bpf 允许为系统调用定义白名单和黑名单,拥有对这些调用进行参数检查的特性,以及用于获取下列任意过滤器返回值(kill、trap、trace、errno)的选项 [15]。seccomp 的最小化配置应该涉及定义具有 kill 作为其过滤器返回值的系统调用的白名单。此白名单的初始内容应该包括基本系统调用(信号处理、读取、写入、退出)。处理逻辑应该从验证架构开始(由于系统调用编号依附于架构),并且随后加载该系统调用编号并且将其与白名单进行比对。如果没有发现良好的匹配,则此进程应该被杀死。可以部署可选的 seccomp 过滤器的额外特性,它可以暂时捕获失败的系统调用并且报告它(而非立即退出)。这可以提供这样的担保,即此系统调用列表(白名单)为最终状态并且无需对其进行更改,除非其应用程序或者应用程序库发生更改
  • (e) 如果使用 Seccomp,由 seccomp 过滤器创建的沙盒必须不能允许使用 ptrace 命令。如果 ptrace 被允许,跟踪者可以修改此进程的系统调用以绕过过滤器,并且由此调用被阻止或者限制的系统调用
  • (f) 一种应该可用的最小化配置特性允许将宿主的容器分割为不同的安全域
  • (g) LKM 应该拥有特性以防止容器的挂载/重新挂载敏感目录以及/或者对于安全性的强制实施至关重要的特定系统目录(Cgroups、procfs、sysfs)的能力
  • (h) LKM 应该拥有特性以便利用上述特性的组合为容器运行时的管理员创建安全配置文件

第 5 章 容器运行时配置的担保要求

如前文 2.5 节所述,用于容器的所有安全性配置参数之中,除了那些用于处理集群管理和计划的以外,都是利用容器运行时提供的 API 设置的。尽管它们中的大多数涉及 Linux 内核特性(名称空间、Cgroups、能力)以及 Linux 内核模块,这些任务被包括在本章中,由于它们是由对 Linux 宿主 OS 接口进行系统调用的容器运行时执行的。本章的总体组织如下:

  • (a) 5.2 节讨论了涉及 Linux 的名称空间特性的配置,它们为不同资源提供隔离
  • (b) 5.3 节讨论了利用 Cgroups 特性的配置,它们主要用于设置资源限制,并且由此防止拒绝服务攻击
  • (c) 5.4 节讨论了利用能力特性的配置,它们允许最小化权限的分配
  • (d) 5.5 节讨论了用于设备隔离的配置,这可以通过利用 Cgroups 和内核可加载的基于标签的强制实施模块的组合来解决
  • (e) 5.6 节讨论了那些可以在启动容器时进行设置,而非利用上述功能预先配置的参数

在分析这些功能之前,5.1 节概述了对于容器运行时本身的配置特性的需求。

5.1 对于安全连接的要求

容器运行时模块利用监听 Unix 套接字并且因此允许该运行时的远程管理的守护进程而实现。在特定情况下,管理组成员有可能将 Unix 套接字替换为 TCP 套接字 [10]。对此 TCP 套接字的任何连接都可能允许攻击者推送并且在高权限模式下运行任何容器,由此赋予它们对于宿主的 root 访问权限。TLS 连接的安全性担保要求涉及双方(容器运行时模块以及用于远程管理的客户端工具)在建立 TLS 会话之前对此连接的加密和认证。

5.2 对于基于隔离的配置的要求

5.2.1 容器进程隔离

对于容器而言,进程隔离是一项核心安全要求,以保证运行于不同容器以及宿主中的不同应用程序的完整性。容器环境中的进程隔离机制应该满足下列要求 [4]:

  • (a) 能够将运行于不同容器中的进程彼此区分开来,以及将其同运行于宿主中的进程区分开来
  • (b) 限制跨容器进程可视性
  • (c) 防止特定类型的攻击,诸如:
    • (i) 运行于一个容器中的进程影响到运行于另一个容器中的进程,通过由 OS 提供的用于进程管理的接口(例如信号和中断)
    • (ii) 运行于一个容器中的进程直接访问属于运行于另一个容器中的进程的内存,通过特殊系统调用(例如 ptrace() 允许调试工具连接被调试的进程的内存)

为了提供进程隔离,用到了一项称为进程 ID(PID)名称空间的 Linux 内核特性。PID 名称空间是一种用于分组进程并且控制它们发现(例如通过 proc 伪文件系统)其他进程并且与其交互(例如发送信号)的能力的机制。PID 名称空间通过 clone() 或者 unshare() 系统调用来创建,并且与一个或者更多容器相关联。首个进程具有标识符 PID 1,后续进程的标识符按顺序增加。因此 PID 名称空间的特性还提供了 PID 虚拟化。位于不同 PID 名称空间中的两个进程可能拥有相同的 PID。

5.2.2 容器文件系统隔离

文件系统隔离的目标是防止从一个容器对另一个容器以及从任何容器对宿主的文件系统对象的非法访问。文件系统是一种 OS 接口,它允许进程存储和共享数据,以及在彼此之间进行交互。容器应用程序对数据的访问由它通过文件系统挂载点对文件系统的访问决定。因此,可以通过使得文件系统挂载点列表对于容器应用程序可见并且可访问来限制对数据的访问。这是通过挂载名称空间实现的。首先,一个命名的挂载名称空间随着一系列文件系统挂载点而被创建。此挂载名称空间随后与某一个只能在这些挂载点上发现并且发出诸如 mount() 或者 unmount() 的系统调用的进程相关联。它还可以操作位于该挂载名称空间中并且可通过这些挂载点访问的文件。下列内容为文件系统隔离安全性解决方案以及它们的限制:

  • (a) 所有基于 Linux 的 OS 虚拟化解决方案使用一个允许容器和宿主之间的挂载隔离的 挂载名称空间,其目的是辅助对于用户和进程可见的环境的自定义。此特性不能保证容器之间的数据隔离。容器从其上一级继承文件系统挂载视图,并且能够访问文件系统的所有部分,即使每一个容器都是在一个新的挂载名称空间中创建的
  • (b) 用于进程的文件系统访问封闭的典型解决方案是通过 chroot() 系统调用,它将某个进程绑定到文件系统层级结构中的树状子结构中,这允许容器同宿主分享资源,通过将其挂载到在容器中可见的树状子结构中。然而,此特性不能提供存在高权限进程(例如具有 CAP_SYS_CHROOT 权限的进程)的情况下的必要保护,这些进程可以绕过 chroot 的限制,由于 chroot() 系统调用只会影响路径解析这一事实
  • (c) 对于文件系统对象的更好的保护可通过修改容器中的进程的 root 文件系统来提供,而非只是修改 root 目录(这是 chroot() 系统调用所允许的)[4]。这是通过 pivot_root() 系统调用启用的,它将旧的 root 文件系统的挂载点移动到新的 root 文件系统中的某个目录下,并且将新的 root 文件系统置于其中。这提供了文件系统层级的保护,由于旧的 root 文件系统可以被卸载,如果这是在容器的挂载名称空间中执行的,因此使得宿主的 root 文件系统对于容器中的进程不可访问
  • (d) 另一种文件系统层级的保护策略是默认禁止某个限制区域中运行的进程挂载或者卸载文件系统,并且强制实施此权限的粒度控制,利用 allow_mount* 命令的选项
  • (e) 另一种强化文件系统隔离的机制是为每一个容器指认一个独立的用户名称空间,这会将用户和组 ID 映射到宿主 UID 和组中的具有较少权限的范围中

由于上述每一种安全性解决方案的限制,对于文件系统的整体保护的担保要求涉及包括挂载名称空间、chroot、pivot_root 和用户名称空间的配置的组合,以用于:

  • 利用挂载名称空间隔离挂载点
  • 利用 chroot() 为每一个进程更改 root 目录
  • 利用 pivot_root() 为每一个进程更改 root 文件系统的可视性
  • 利用用户名称空间限制用户访问范围

5.2.3 容器 IPC 隔离

容器的进程间通信(IPC)隔离意味着一个容器中的进程必须被限制为仅可在同一容器内部通过特定的 IPC 简单信道进行通讯。IPC 对象(或者与之相关联的机制)可以是基于文件系统的 IPC 对象或者并非基于文件系统的。基于文件系统的 IPC 对象,诸如域套接字或者命名管道,可以利用挂载名称空间和 pivot_root 特性的组合来进行隔离(见上文 5.2.2 节),由于它们阻止进程访问其自身容器以外的文件系统路径。

然而,还存在其他 IPC 对象,诸如 System V IPC 对象、信号量集合(数组)、共享内存片断,以及消息队列等。在 Linux 中,这些 IPC 对象可以借助允许创建完全不相交的 IPC 对象集合的 IPC 名称空间而被隔离开来。每一个 IPC 名称空间拥有其自身的 System V IPC 标识符集合以及自身的 POSIX 消息队列文件系统。在一个 IPC 名称空间中创建的对象对属于该名称空间的成员的所有其他进程可见,而对于其他 IPC 名称空间的进程不可见。对于某一个进程可访问的 IPC 对象可以利用 ipcs 命令列出,或者利用 ipcrm 命令移除。

5.2.4 容器网络隔离

容器的网络层级的隔离通过网络名称空间特性而提供。对于所创建的每一个网络名称空间,一组网络设备、IP 地址、 IP 路由表、/proc/net 目录,以及端口号可以与之相关联。每一个容器可以拥有其自身的虚拟网络设备和应用程序以绑定到每一个名称空间的端口号空间。宿主系统中的适当的路由规则可以将网络数据包指引到与某个特定容器相关联的网络设备。因此可能拥有例如同一宿主系统上的多个容器化的网络服务器,其中每一个服务器都在其(每个容器的)网络名称空间中绑定到 80 端口。

网络连接性是运行于容器中的生产级应用程序,诸如网络应用程序和多层应用程序,的核心要求。容器可以通过一种称为覆盖网络的逻辑 IP 网络连接起来。容器平台(由容器、容器运行时、宿主 OS 和物理宿主构成)的典型网络配置涉及在容器宿主上创建网桥。宿主上的每一个容器都连接到该网桥。路由器在其混合模式中从其桥接接口捕获以太网数据包,被捕获的包通过用户数据报协议(UDP)转发到运行于其他容器宿主中的路由器端。这些 UDP “连接”是双工的,可以穿透防火墙,并且可以被加密 [12]。每一个容器通过第 2 层(链路层)虚拟网络接口(VNI)连接到该网桥,该接口具有有效的链路层地址或者用于第 3 层连接性的网络地址转换(NAT)。Linux 的第 2 层网络隔离基于网络名称空间的概念,这允许创建若干网络栈以便提供一种完全独立于容器的视图 [4]。

使用第 2 层 VNI 的网络隔离的最简单配置涉及定义一对虚拟连接以太网(veth)接口,其中一个接口被指认给与容器相同的网络名称空间,而另一个被指认给宿主名称空间。这两个接口之间的虚拟连接随后被建立起来,因此将容器同物理网络连接起来。有两种选项以启用这种连接 [4]:

  • (a) 网桥设备:veth 接口和宿主物理接口通过虚拟网桥设备连接起来。在此选项中,所有容器和宿主接口被连接到同一链路层网桥,并且因此接收该网桥的所有链路层流量
  • (b) 路由表:另一个选项是利用路由表在(容器所被连接到的)虚拟网络接口和(驻留于宿主上的)物理网络接口之间转发流量。在此选项中,只有当显式地提供了网络路由时,容器才能进行彼此之间的通讯

安全性分析:由这两种选项提供的网络隔离功能强制容器进程使用被指认的虚拟网段或者被指认的网络路由(例如通过 VPN 连接)。在这两种选项之间,路由表的使用相对于网桥设备解决方案提供了略高一些的安全性担保,由于后者允许容器地址对于连接到该网桥的所有容器可见。

为容器提供网络连接性的另一种方式是使用 MACVLAN 接口 [13],它也允许每一个容器拥有其独立的链路层地址。虚拟以太网端口汇聚器(VEPA)是最广泛地应用于此类容器隔离选项的配置模式。然而,仅当基于名称空间的方式通过基于标签的访问控制以及同来自其他全局名称空间的进程进行隔离而得到加强时,才可能在进程层级对容器提供完整的网络隔离担保。

5.2.5 容器的用户和组层级的隔离

有些进程可能需要 root 权限的某个子集。用户名称空间特性可用于将某些用户 ID 的权限限制为该所需的子集。用户名称空间将用户和组 ID 号空间隔离开来。换言之,某个进程的用户和组 ID 在某个用户名称空间内外可以不同。在此,最为有趣的案例是,某个进程可以在某个用户名称空间以外拥有正常的低权限用户 ID,而同时在此名称空间内拥有用户 ID 0。这意味着此进程在此用户名称空间内拥有完整的 root 操作权限,而在此名称空间以外则只有低操作权限。

从 Linux 3.8 开始,低权限进程可以创建用户名称空间,这为应用程序的有趣的全新的可能性开辟了道路。由于在其他情况下的低权限进程现在可以在其用户名称空间内保持 root 权限,低权限应用程序现在可以拥有对于之前仅限于 root 的功能的访问权限 [4]。

5.3 对于资源限制解决方案的要求

在 Linux 容器环境中,应对拒绝服务攻击的主要保护机制是允许设置不同资源限制的 Cgroups 特性。“限制”规范特性不仅限制诸如 CPU、内存、存储等硬件资源,也适用于进程和任务。除了限制特性以外,Cgroups 允许指认一系列潜在的“资源消耗大户任务”,它们可以通过发送 SIGSTOP 信号被冻结,并且在随后发送 SIGCONT 信号而解冻 [11]。

除了其防止拒绝服务攻击的主要作用以外,Cgroups 特性还可以提供额外的网络层级保护,通过某种方法(利用网络分类 Cgroup)对网络数据包以某个“类标识符”的值进行标记。这随后可以被用作参数以过滤特定的包。(这个类标识符的值也可被用于基于服务质量(QoS)要求的优先级处理,尽管此特性属于性能增强而非严格属于安全性。)

下列表格提供了 Cgroups 特性能够对其设置资源限制或者访问控制的硬件资源列表:

表 1——利用 Cgroups 的 Linux 资源限制

资源 “限制”特性或者访问控制
CPU 为一组进程指定 CPU 数量或者“CPU 份额”的值
内存 用于一组进程的“硬”和“软”内存分配单元
BLKIO 设置硬盘读写速度、每秒操作数、队列控制,以及由主要和次要数值所指认的等待时间;相对于文件系统的特定控制提供更多的粒度访问控制
设备 创建设备白名单,基于 (a) 类型(字符设备还是块设备)或者 (b) 主要和次要数值

Cgroups 配置应该提供下列担保:

  • (a) 它不应该暴露容器宿主信息,诸如通过 dmesg 暴露内核环缓冲,这可能协助内核漏洞利用或者信息泄漏
  • (b) 它不应该允许本地硬盘访问,即使是在用户名称空间内通过原生硬盘、设备或者 make node(mknod)访问挂载受限的名称空间 [11]

5.4 对于容器的最小化权限配置的要求

如前文所提到的,Linux 的能力特性可用于分割 root 权限集合。所有容器运行时产品,诸如 LXC、Docker 以及 CoreOS Rkt,都带有默认配置文件,其中,容器的某些能力被启用而某些被禁用 [11]。由于运行于容器中的应用程序的权限需求,某些默认值必须被修改(即某些默认被启用的能力需要被禁用,而某些默认被禁用的能力需要被启用)。然而,对于托管于容器中的大多数应用程序,在配置 Linux 的能力特性时,下列担保要求必须被满足:

  • (a) 提供权限以操纵非名称空间的内核参数(例如系统时间)的能力将会拥有该参数的效果,此参数的修改不仅是对于该容器,也是对于宿主和所有其他容器的。因此这样的能力(例如 CAP_SYS_TIME)不应该被启用
  • (b) 提供几乎等同于 root 的宽泛权限集合的能力不应该被启用(例如 CAP_SYS_ADMIN
  • (c) 无需启用能力 CAP_SYS_MODULE,它允许加载和卸载内核模块,由于这会导致不安全的权限提升
  • (d) 能力特性应该总是和用户名称空间配合使用,由于任何错误地启用某些能力而导致的进程权限提升将会被限制在名称空间内

5.5 对于设备隔离解决方案的要求

在 Linux 中,对设备的访问是通过设备结点实现的,设备结点是为宿主的设备驱动程序提供接口的特殊文件。设备结点同文件系统的剩余部分分隔开来,并且它们的结点被置于 /dev 目录中。这些结点对于名称空间并不警觉。设备结点的创建是通过 udevd 守护进程发出 mknod 系统调用而实现的。进程创建设备结点(用于访问块设备或者字符设备)的许可是由 CAP_SYS_MKNOD 能力提供的。如果对应的设备将要在容器之间或者不同容器与宿主之间共享,则容器被赋予对设备结点的访问。然而,设备结点是安全敏感的,由于它们将接口(特别是存储接口)暴露给运行于内核空间的代码,这可能被滥用以获得非法数据访问、权限提升或者挂载其他攻击。

在容器之间提供设备层级的隔离的一种可能的解决方案是使用“设备名称空间”,如果被引用的输入/输出(物理)设备是对于名称空间警觉的。不幸的是,很多 Linux 内核发行版并不支持设备名称空间特性。如果可用,此特性可用于为每一个容器创建虚拟设备,它们可以被多路传输以访问某个物理宿主设备。更进一步地,如果控制物理设备的 Linux 设备驱动程序对于名称空间并不警觉,并且这些设备假设只有一个控制它们的主控结点,对于它们的访问权限很难被安全地赋予低权限的容器,除非该设备只由单一容器专属使用。

在缺少设备名称空间的情况下,两种特性被用于控制容器对设备的访问。它们是:(a) 控制组,或者 Cgroups;以及 (b) 基于标签的访问控制。设备的 Cgroups 子系统被用于创建白名单,基于类型(即字符设备还是块设备)以及设备的主要和次要编号来针对设备格式化。通配符“all”适用于所有设备类型以及主要和次要编号,并且通常在显式地将设备列入白名单之前被用作默认的拒绝 [11]。

在 Linux 环境中有两种基于标签的强制执行方式:安全增强式 Linux(SELinux)和 AppArmor。在 SELinux 中,类别标签被应用于进程和数据/设备,并且进程对于资源的访问将会被拒绝,如果它不属于正确的分类。例如,某个特定的标签可以被应用于某个给定的容器 X,并且将要由该容器消费的数据被指认给相同的标签。由于指认类别过程的灵活性,SELinux 可以被用于强制实施精细粒度策略。AppArmor 是另一种基于标签的系统,它提供基于路径的访问控制(与 SELinux 中的文件系统结点相对)。对于特定应用程序、进程或者容器,限制条件可以被聚合起来以定义配置文件。所有这些基于标签的系统的共同的弱点在于,它们所提供的控制可以通过直接执行系统调用而被破坏。

因此,对于设备隔离解决方案的担保要求包括:

  • (a) 所有容器必须被防止创建新的设备结点,并且 CAP_SYS_MKNOD 能力对于它们不应该被启用
  • (b) 容器内的所有挂载点应该设置 nodev 标识(通过利用 mount 命令的 nodev 选项)以防止它们被用于创建文件以访问设备驱动程序
  • (c) 所有容器应该仅被允许访问下列设备的集合,由于它们被表征为安全的 [4],基于下列给出的观察:
    • 完全虚拟设备——诸如伪终端和虚拟网络接口;此安全担保来自这些设备为每一个容器显式地创建并且未被共享这一事实
    • 无状态设备——诸如 random、null 及其他;在所有容器之间共享这些设备的同时仍然能够保持宿主安全,由于它们是无状态的
    • 对于用户名称空间警觉的设备——如果此设备(通过设备驱动程序代码)支持对于对应用户名称空间中的进程的验证能力,则这样的设备可以被安全地暴露给容器,由于特定的限制条件将会被强制实施
  • (d) 如果 Cgroups 和基于标签的强制执行系统都被用于控制对设备的访问,应当谨慎以确保它们各自的规则不会产生冲突

5.6 对于容器启动选项的要求

每一种容器运行时产品都有带有众多参数的命令以启动容器。与此命令的安全使用相关联的担保要求被叙述为一组应该被避免使用的选项 [4]。作为最佳安全实践,容器不应该使用那些当它被启动时将会共享与容器宿主相关联的任何名称空间的选项 [11]。如若不然,这可能不仅允许容器查看与该名称空间相关联的资源/对象,而且允许操纵这些资源/对象,通过破坏由容器的名称空间的静态配置提供的隔离。下表提供了这样的名称空间的列表,对于它们而言,共享宿主侧的对应物不应该被用于容器启动选项。

表 2——禁止的容器启动选项

名称空间/范例资源-对象 简述 安全威胁
Unix 分时系统(UTS) 所有容器被指认给其自身的 UTS 名称空间,因此无需获知宿主的 UTS 名称空间 容器中的进程可以看到并且操作宿主的主机名和域
IPC/共享内存片断 应用程序模块之间的用于进程间通信的共享内存片断被设置以用于快速通讯,由于它们比 REST API 调用更快 容器中的进程可以看到并且操作宿主的 IPC 对象
文件系统 宿主敏感的目录不应该以读写模式挂载为容器卷 赋予容器修改这些目录中的文件的能力,带有潜在破坏宿主安全的风险
在容器启动命令中设置 net=host 容器的网络模式不应该被设置为等同于宿主 这将会赋予容器只有宿主才应该拥有的权限(例如关闭其自身)或者访问只有宿主才需要访问的网络服务的权限
将容器端口公开至宿主 这被用于设置出入该容器的通讯 公开所有接口的默认选项不应该被使用;通过显式指定端口应该被绑定到的接口,出入该容器的流量被限制在给定的接口
容器间通讯 如果存在,此选项允许任何类型的容器间通讯,它必须不能被启用;与之相反,在两个需要通讯的容器之间必须显式设置通讯信道 任何被攻击的容器可以攻击宿主上的任何其他容器

除了涉及同宿主共享的对象的容器启动选项以外,有一些专门适用于容器的参数应该在容器启动时被设置:

  • (a) 容器应该总是被启动为具有一定的内存限制,以防止拒绝服务攻击,或是某些应用程序泄漏内存,以至于它最终将会消耗宿主的全部内存
  • (b) 容器应该总是通过指定 CPU 份额数值而启动。默认值(总 CPU 数/容器数)可能对于某些容器并不够用,导致拒绝服务。指认给某一容器的 CPU 份额数值应该使得没有容器可以导致具有默认设置的其他容器得不到足够的资源。更进一步地,如果存在这样一组容器,其在 CPU 使用上相对于其他容器占据主导地位,则较低的默认值应该被指认给该组中的容器,以保证 CPU 份额的公平分配
  • (c) 如果宿主 OS Linux 发行版支持某种基于标签的系统(例如 SELinux),则应该设置策略模板。容器引擎应该被启动为带有选项以识别该模板,并且容器启动 API 应该拥有选项以识别此策略模板参数,并且将其作为启动参数的一部分而包括进来
  • (d) 容器应该被启动为仅有“必要的”能力,通过在初始时放弃所有能力,并且随后仅添加必要的能力。下列能力通常不应该存在于容器配置中(即 NET_ADMINSYS_ADMINSYS_MODULE),由于它们提供了超出大多数部署所必要的权限

第 6 章 镜像完整性解决方案的担保要求

容器镜像的完整性至关重要,由于它们被转换为运行着的实例,其中的一些可能还会托管关键任务应用程序。容器安全性指南 一文所覆盖的镜像反制措施包括关于监视镜像以查找恶意软件以及其他漏洞、适当的镜像配置、同镜像文件隔离机密信息,以及通过密码学签名以及常规更新来保证镜像中的信任等方面的建议。执行这些建议所需的安全性解决方案应该包括下列担保要求:

  • (a) 应该存在方式以创建将每一个镜像连接至其基本镜像的元数据
  • (b) 应该存在特性以自动重建镜像,如果与之连接的基本镜像发生更改 [6]
  • (c) 如果对基本镜像或者被依赖的镜像进行了任何修改(例如为漏洞打补丁),不应该对运行着的容器进行修改,与之相反,应该利用修改过的镜像重建对应的镜像,并且重新启动容器。因此,对于任何服务都需要维护单一的主镜像或者黄金镜像
  • (d) 如果将“镜像签名”解决方案用于对每一个镜像进行数字签名和唯一性识别,下列要求应该被满足 [6]:
      1. 应该存在强壮的密钥管理机制以使得密钥攻击的可能性最小化。一种方式是拥有 PKI 系统以便为每一位开发者签发专门用于签名镜像的证书。与此证书相关联的私钥将会成为“签名密钥”以被用于签名某个库中的所有容器镜像
      1. 必须通过在签名的容器镜像中嵌入过期时间戳来化解重放攻击。或者,某个特殊的密钥可以被用于签名该库的元数据,以保证该库中的镜像不包含带有有效签名的不新鲜版本的镜像
  • (e) 除了利用数字签名为镜像创建唯一的身份标识以外,此镜像的单个组件的完整性可以通过为每一个组件使用诸如配对的密钥/值等标签来保证
  • (f) 镜像应该以这样的方式来创建,以使得其中的应用程序不能被用于任何权限提升攻击。这可以通过禁用 chmod a-s 命令以移除 suid 位,或者移除其中的 setuid 和 setgid 二进制文件来实现 [6]。

第 7 章 镜像注册表保护的担保要求

容器安全性指南 一文中提议的注册表反制措施包括开发对于注册表的安全连接,以及保证注册表中不包含过时的、易受攻击的镜像,通过某种自动化的过程将其删除,或者通过使用专用的版本号来控制其意外部署。某些与这些反制措施并不相关,但是对于涉及出入注册表的镜像的创建、发布和移除过程仍然至关重要的担保要求包括:

  • (a) 能够访问注册表的帐户数量必须被限制,由于某些环境中的普遍威胁是帐户劫持,如果一大批各式各样的帐户都拥有对某个容器注册表的访问权限。此类环境之一是由提供容器服务的云服务提供商维护的注册表
  • (b) 对于创建容器镜像注册表以及为注册表添加或者移除内容的许可必须以密码学方式来保护

第 8 章 编排器功能的担保要求

在容器化的基础设施中使用编排器平台(由一套工具组成)的本意是执行下列功能:

  • 允许定义集群(一个命名的容器宿主的组,可以视为单一实体进行管理)以及将容器编排至集群中。集群的配置应该支持指定下列参数,诸如保留的 CPU/内存数量、副本(即要运行的相同容器的重复备份)数量,以及判断容器应该持续运行还是被下线的环境
  • 允许容器在不同集群宿主中的自动部署(容器计划),这是通过整合不同的自动化工具以便将自动化脚本作为编排工作流的一部分而执行,并且获取来自这些自动化任务的反馈和状态结果而实现的。此类整合依赖于自动化工具提供的接口以及它们所遵循的格式类型(开放或者封闭)[14]
  • 供货或者定义新的容器宿主,并且将其连接到现有的集群

容器安全性指南 一文中提议的编排器反制措施包括基于作为参数的宿主、容器、镜像的管理行为的粒度访问控制、使用强凭证和目录的企业级认证服务,以及基于运行于其中的应用程序的敏感度级别将容器隔离至独立的宿主。除了这些反制措施以外,编排器应该满足下列安全性担保要求:

  • (a) 集群应该拥有能力以记录日志并且监视单个容器的资源消耗特征,以避免资源使用中的意外峰值,由于这会导致关键资源的不可用性
  • (b) 编排器平台必须在具有多于一种宿主 OS 的容器化的基础设施中可用。换言之,所使用的编排器工具必须对于容器宿主 OS 中立。将不同的工具用于不同的容器宿主 OS 平台将会增加这些环境中的拒绝服务攻击的可能性,由于企业不能获取在其整个容器化的基础设施中运行的所有容器的资源使用的全局视图

第 9 章 某些安全性解决方案的副作用

当在安全性目标(例如文件系统隔离)的上下文环境中讨论某种安全性解决方案(例如使用挂载名称空间)时,某些增强解决方案被推荐,由于被讨论的解决方案就其自身而言不能满足此目标。然而,对于某些安全性解决方案,无论采用何种增强控制,都会为某些容器功能的实用性和性能施加某些限制。尽管它们的直接影响只是功能和性能方面的,它们可能对于某些安全性参数具有间接影响。例如,在设置系统调用过滤器(带有白名单和黑名单)时使用 Seccomp 作为安全性解决方案(由于系统调用对于名称空间并不警觉,因此排除了使用名称空间特性的可能性)时,恶意进程的存在可能引发容器之间的泄漏。更进一步地,被允许的系统调用的选择是基于容器中的一组当前应用程序的,则此安全性解决方案具有引入应用程序不兼容性的潜在可能,由于应用程序可能出于负载均衡等原因在容器之间迁移。

第 10 章 总结和结论

此文档中所分析的安全性解决方案可以总结如下:

  • (a) 利用诸如 TPM 和 vTPM 等基于硬件的可信根解决方案为容器栈的诸如 Linux(宿主 OS)、容器运行时以及容器等软件组件提供完整性的认证和证明
  • (b) 利用基于硬件的保护机制将容器彼此屏蔽开来,以及将容器同诸如 Linux 内核等高权限软件屏蔽开来,通过使用由硬件架构提供的安全执行环境(例如 Intel SGX)
  • (c) 利用 Linux 内核特性(名称空间、Cgroups、能力)以及可加载内核模块(LKM)特性来保护 Linux 内核本身,以及保护某个容器不受其他容器的影响
  • (d) 用于容器运行时、容器镜像、容器注册表以及容器编排器工具的保护措施

通过以上分析得出的结论是,每一种安全性解决方案必须满足某些安全性担保要求以便有效地提供必要和充分的安全性保证。

附录 A——首字母缩略词

此论文中使用的部分选定的首字母缩略词和缩略语定义如下:

  • EPC:enclave 页缓存
  • IPC:进程间通信
  • MEE:内存加密引擎
  • NAT:网络地址转换
  • PID:进程 ID
  • PKI:公钥基础设施
  • SGX:Software Guard eXtensions
  • TPM:可信平台模块
  • UDP:用户数据报协议
  • UTS:Unix 分时系统
  • VM:虚拟机
  • VNI:虚拟网络接口

附录 B——参考文献