随着云计算的蓬勃发展,云原生的概念于2013年被提出,Pivotal 公司的 Matt Stine 在概念中提出了云原生的4个要点:DevOps、持续交付、微服务、容器。而在 2015 年 Google 主导成立了云原生计算基金会(CNCF),CNCF 也给出了对云原生(Cloud Native)的定义,其中包含三个方面:1)应用容器化;2)面向微服务架构;3)应用支持容器的编排调度。
随着近几年来云原生生态的不断壮大,所有主流云计算供应商都加入了该基金会, CNCF 基金会中的会员以及容纳的项目越来越多,原先的定义已经限制了云原生生态的发展,到了 2018 年 CNCF 为云原生进行了重新定位,同时指出云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。围绕这些概念、定义和代表技术,最为基础的就是容器和微服务。在容器应用之前,相关的云计算的应用多数运行于虚拟机上,但虚拟机会有额外的资源浪费和维护成本,并且其启动速度较慢。正是容器技术所具有的占用资源少、部署速度快和便于迁移等特点,助力了云原生生态的蓬勃发展,其中 Docker 和 Kubernetes 是企业容器运行时和容器编排的首要选择。
而于此同时,如何保证云原生环境的安全性也在不断受到挑战。在云原生技术应用的过程中,大多数企业都遇到过不同程度的安全问题,无论是前两年爆出的某著名车企的容器集群入侵事件,还是容器官方镜像仓库 Docker Hub 存在恶意镜像,用户在享受云原生相关技术便利的同时,也产生了极大的安全担忧。而作为云原生的基石——容器的安全性更是重中之重,为了满足云原生业务上对安全防护工具的全面性、便捷性以及性能上的要求,围绕着容器运行时安全的多个内核安全特性也在不断发展,本文将对近年来针对容器运行过程中的安全加固技术进行逐一介绍。(在本文中,若无特殊说明,容器指代 Docker 容器)
1、容器安全概述
在实现云原生的主要技术中,容器作为支撑应用运行的重要载体,为应用的运行提供了隔离和封装,成为云原生应用的基础设施底座。与虚拟机不同的是,虚拟机模拟了硬件系统,每个虚拟机都运行在独立的 Guest OS 上,而容器之间却共享操作系统内核,并未实现完全的隔离。若虚拟化软件存在缺陷,或宿主机内核被攻击,将会造诸多的安全问题,包括隔离资源失效、容器逃逸等,影响宿主机上的其他容器甚至整个内网环境的安全(下图展示了 VM 和容器在系统架构上的差异)。
据《Sysdig 2022 云原生安全和使用报告》显示,超过75%的运行容器存在高危或严重漏洞、62%的容器被检测出包含 shell 命令、76%的容器使用 root 权限运行。鉴于云原生的攻击手段的独特性, 安全组织 MITRE 的对抗战术和技术知识库(ATT&CK 框架)在2021年推出了专门针对容器的攻击模型。云原生安全在近年来获得了大量的关注。
Google 在其 GCP 上讨论容器安全风险时,依据容器风险的来源,将其分为了三个方面:
而 Google 的这个分类方法,其实也可以归结抽象为对容器生命周期中三个过程的安全:
构建时安全:在容器镜像构建过程中,分析构建镜像时所使用的命令和配置参数,还原镜像文件构建过程,掌握命令使用的敏感操作,以及分析镜像文件是否包含密码、令牌、密钥和用户机密信息等敏感信息。同时,分析镜像的软件组成,发现镜像文件中包含的恶意文件、病毒和木马,以及所使用的依赖库和组件存在的安全漏洞,避免镜像本身存在的安全风险。
部署时安全:分析镜像无风险后,镜像被提交至镜像仓库。在该阶段,将检查容器环境的镜像仓库配置,确保使用加密方式连接镜像仓库。当镜像仓库中新增镜像或使用镜像创建容器时,自动化校验镜像签名或MD5值,确保镜像来源可信且未被篡改,一旦发现镜像来源不可信或被篡改,禁止使用该镜像创建容器。
运行时安全:当确认镜像安全后,进入到容器运行阶段。该阶段主要是是保证容器运行环境的安全,防止容器出现异常行为,这其中就包括主机环境配置安全、容器守护进程配置安全、容器应用的运行安全。
在容器生命周期的三个过程中,攻击者往往是在前两个阶段部署相关的恶意代码,在容器运行时对环境真正执行相关的攻击指令。因此,容器运行时相比于其他两个阶段更直接、也更容易分析出环境中的恶意行为。与其他虚拟化技术类似,逃逸也是针对容器运行时存在的漏洞最为严重的攻击利用行为。攻击者可通过利用漏洞“逃逸”出自身拥有的权限范围,实现对宿主机或者宿主机上其他容器的访问,其中最为简单的就是造成宿主机的资源耗尽,往往会直接危害底层宿主机和整个云原生系统的安全。根据风险所在层次的不同,可以进一步展开为:危险配置导致的容器安全风险、危险挂载导致的容器安全风险、相关程序漏洞导致的容器安全风险、内核漏洞导致的容器安全风险:
危险配置导致的容器安全风险:用户可以通过修改容器环境配置或在启动容器时指定参数来改变容器的相关约束,但如果用户为一些不完全受控的容器配置了某些危险的配置参数,就为攻击者提供了一定程度的可以攻击利用的安全漏洞,例如未授权访问带来的容器安全风险,特权模式运行带来的容器安全风险。
危险挂载导致的容器安全风险:将宿主机上的敏感文件或目录挂载到容器内部,尤其是那些不完全受控的容器内部,往往也会带来安全风险。这种挂载行为可以通过环境配置来设定,也可以在运行时进行动态挂载,因此这里单独地归为一类。随着应用的逐渐深化,挂载操作变得愈加广泛,甚至为了实现特定功能或方便操作,使用者会选择将外部敏感资源或文件系统直接挂载入容器,由此而来的安全问题也呈现上升趋势。例如:挂载 Docker Socket 引入的容器安全风险、挂载宿主机 procfs、sysfs 引入的容器安全问题等。
相关程序漏洞导致的容器安全风险:所谓相关程序漏洞,指的是那些参与到容器运行、管理的服务端以及客户端程序自身存在的漏洞。例如,CVE-2019-5736、CVE-2021-30465、CVE-2020-15257等存在于 Container Daemon、runC 上的容器安全漏洞。
内核漏洞导致的容器安全风险:Linux 内核漏洞的危害之大、影响范围之广,使得它在各种攻防话题下都占有一席之地,特别是在容器环境中由于容器与宿主机共享了内核,攻击者可以直接在容器中对内核漏洞进行利用攻击。近年来,Linux 系统曝出过无数内核漏洞,例如最有名气的漏洞之一——脏牛(CVE-2016-5195)漏洞也能用来进行容器逃逸。