0x00 前言
前面我们介绍了风险、威胁和缓解措施的基本概念,了解了什么是风险管理框架和威胁模型。那么我们该如何对容器进行威胁建模呢?首先,我们先思考:参与者有哪些?
0x01 参与者
一个良好的威胁建模方式往往从考虑参与者开始,在容器的世界里,这可能包括:
- 外部攻击者:试图从外部访问系统环境的人。
- 内部攻击者:已经成功地访问了部分系统环境的人。
- 恶意的内部参与者:对系统环境有一定权限的恶意的访问者,例如恶意的开发人员和管理员。
- 无意中的内部参与者:对系统环境有一定权限的可能会意外造成问题的参与者。
- 应用程序进程:进程虽然不是有意损害您的系统环境的有意识的个体,但它可以通过编程的方式对系统环境进行访问。
这些参与者都有一定的权限合集,我们可以站在他们的角度去思考下面的问题:
- 他们通过凭据可以获得哪些访问权限。例如,他们是否可以访问容器所在的宿主机上的用户账号?
- 容器中包含哪些权限。例如,在Kubernetes中,你可以使用 RBAC(role-based access control,基于角色的访问控制)鉴权来为用户管理集群资源的访问权限,也可以使用匿名用户。
- 都有哪些网络访问权限。例如,部分系统是否包含在VPC(Virtual Private Cloud,虚拟私有云)中?
在Cilium 的官方文档中,我们看到了Cilium的团队也使用这种方式进行威胁建模。
0x02 容器威胁模型
想要攻击一个容器化的环境,这可有太多的可能的方式了。但我们有个方法可以尽量地都找到它们,那就是:从容器的生命周期的各个阶段去考虑潜在的攻击向量。
2.1 应用程序代码的漏洞
容器的生命周期始于开发人员编写的应用程序代码,这些代码和所依赖的第三方库可能包含着成千上万个已被披露的漏洞。如果应用程序包含这些漏洞,那么对于攻击者而言,它就是个“香饽饽”。
为了避免运行中的容器包含已知的漏洞,最好的方法是对镜像进行扫描,我们将在《第 7 课:镜像中的软件漏洞》中进行详细的讲解。
需要强调的是,镜像扫描需要周期性进行。白帽子会不断地从已知的代码中发现新的漏洞,镜像扫描所依赖的漏洞库也需要不断地更新。不仅如此,容器中的组件也会随着时间的推移而渐渐地过时,所以也需要更新安全补丁。
此外,一些镜像扫描器还能扫描镜像中的恶意软件。
2.2 容器镜像的错误配置
应用程序代码写完后,开发人员会构建一个镜像,将应用程序容器化。
但构建镜像时,也会带来很多隐藏的风险点,这些风险可能会导致之后运行的容器被攻击利用。例如:将镜像配置成以root 用户的身份运行;赋予它远超过实际使用所需要的更多的主机权限。
这部分的内容,我们将在《第 6 课:容器镜像》中进行讲解。
2.3 构建机上的攻击
如果攻击者能够影响甚至修改镜像的构建方式,那么镜像可能会被插入恶意代码,然后攻击者再让这些恶意代码在生产环境中运行。
并且,在构建环境中建立落脚点是攻破生产环境的基石,这部分内容我们也将在《第 6 课:容器镜像》中进行讲解。
2.4 供应链攻击
镜像构建成功后,我们会将其推送到镜像仓库中,若需要运行,我们只需要从镜像仓库中拉取镜像即可。
但您又怎么知道您所拉取的镜像与之前推送的镜像完全相同呢?它们有没有可能会被篡改?
要知道,若攻击者可以在构建环境和部署环境之间修改甚至替换镜像,那么他完全有可能在您的部署环境中运行任意代码。
这也是我们在《第 6 课:容器镜像》中将讨论的话题。
2.5 错误配置的容器
正如前面所说,我们可能会赋予容器一些不必要的、没有经过规划的权限。这部分内容我们将在《第 9 课:打破容器之间的隔离》进行详细说明。
友情提示:若您从互联网中下载了一些YAML配置文件,例如docker-compose.yaml
,在使用之前请确保:这些配置文件没有包含一些不必要的权限与配置。
2.6 有漏洞的宿主机
容器最终是要在宿主机上运行的,所以您还需确保这些宿主机没有运行着易受攻击的应用程序和组件,例如:一些包含着已知漏洞的旧版本的编程组件。
最好的方法是:尽量减少安装在宿主机上的软件数量以减少攻击面,并且还需要根据最佳安全实践来对宿主机进行正确的配置。
这部分内容,我们将在《第 4 课:容器之间的隔离》进行深入讲解。
2.7 暴露的secret
应用程序代码通常需要凭证、令牌(即token)或者是密码才能够与系统中的其他组件进行通信。
若对应用程序进行容器化,您还需要将这些敏感数据作为secret 的值传递到容器中。
传递secret 的方式有哪些呢?这些我们将在《第 12 课:传递 secret 到容器中》中进行讲解,并分析各种方法的安全性。
2.8 不安全的网络
容器通常要与其他容器进行通信,或者需要与外部环境进行通信,我们将在《第 10 课:容器网络安全》中讨论容器的各种网络连接方式。
然后在《第 11 课:使用TLS在组件之间建立起安全的连接》中讲解如何在组件之间建立起安全的连接。
2.9 容器逃逸漏洞
像 containerd 和 CRI-O这些容器运行时已经相当经得起实战的考验并被广泛地使用了。但它们仍然可能存在着一些未被发现的漏洞,这些漏洞可能会导致运行在容器中的恶意代码逃逸到宿主机上。
2019年,波兰的安全研究员Adam Iwaniuk 和 Borys Popławski 在参加完CTF竞赛过后,便萌生了“研究基于Namespace的沙箱逃逸的方法”的想法,此后便发现了著名的CVE-2019-5736漏洞,该漏洞也被称为Runcescape,博客What You Need to Know About the RunC Container Escape Vulnerability对该漏洞进行了很好的总结,有兴趣的读者可以自行查看。
你将在《第 4 课:容器之间的隔离》中了解到一些可以限制容器内的应用程序的行为的隔离机制。
对于一些核心的应用程序而言,容器逃逸的后果会非常严重,所以您需要考虑更加强大的容器隔离机制,详情请看《第 8 章:加强容器之间的隔离》。
0x03 拓展阅读
其他的攻击向量超出了本次课程所涵盖的范围,但是我们不得不简要地提示一下:
- 应用程序的源代码通常会存储在代码仓库中,理论上来说这些代码仓库也有可能会遭到攻击,进而导致应用程序会被破坏。因此,您需要确保用户对代码仓库进行访问控制的权限得到了适当地管理。
- 宿主机之间通常通过网络进行连接,并且使用VPC来确保安全性,然后再连接到互联网中。在传统的部署环境中,您需要安全的网络配置、防火墙以及身份访问管理系统来确保宿主机(或虚拟机)不被攻击者所访问,这些在云原生环境中仍然适用。
- 容器通常在一些编排工具中运行,例如Kubernetes、Docker Swarm或Hashicorp Nomad。如果这些编排工具的配置是不安全的,那么其访问控制没有得到有效地管理,这也会给攻击者提供额外的攻击路径,从而影响到部署环境的安全性。
此外,如果您对Kubernetes 部署环境中的威胁模型感兴趣。可以阅读以下资料:
- CNCF的Kubernetes Threat Model
- CNCF的金融用户组发布的基于STRIDE方法创建的Kubernetes攻击树
0x04 总结
本文,我们分享了对环境进行威胁建模的统一的方法和思路,即:考虑环境的参与者是谁?他们可能具备的权限合集有哪些。然后,我们基于容器的生命周期的各个阶段所潜在的攻击向量,对容器进行了威胁建模。此外,我们还提供了许多拓展阅读的资料,方便读者自行学习。
很多云原生安全爱好者在第一次学习云原生安全的时候,要么一头扎进技术细节中,以至于“管中窥豹,可见一斑”;要么沉迷于各种防护理论体系,最终无法将方案落地。
掌握技术实现的基础原理,同时又有一个全局的防护观对于学习云原生安全而言至关重要。接下来,我们将根据这个容器威胁模型一层层剖析容器防护的基础技术与原理。
本文干货多多,建议收藏~
更多分享,关注微信公众号:喵苗安全,回复【K8S威胁模型】获取文件下载链接