vlambda博客
学习文章列表

从log4j2漏洞看云原生架构下的安全建设与安全运营

前言

近年来,云原生架构被广泛的部署和使用,业务容器化部署的比例逐年提高,对于突发重大漏洞等0day安全事件,往往给安全的应急带来重大的挑战。例如前段时间广受影响的重大漏洞的爆发,可以说是云原生架构下安全建设和安全运营面临的一次大考。


  1. 漏洞处置回顾

漏洞爆发后,第一时间关注的一定是攻击者能否利用漏洞攻击业务系统,可以通过哪些方式实施攻击。对于容器环境,从攻击视角来看,通常可以有以下几种入侵途径。

1)通过容器主机实施攻击。这种通常是由于主机配置问题引起,例如对公网开放并且未开启认证的Docker RemoteAPI,或者是未开启认证的Kubernetes API Server。

2)通过脆弱的容器实施攻击。这种类型攻击主要以容器环境中部署应用程序的脆弱性作为攻击突破口。

3)通过投毒的镜像实施攻击。主要通过对公共仓库中的镜像进行投毒,当镜像被拉取运行时,即可执行相关的攻击操作。

1.1 攻击者可以做什么

本次log4j2漏洞的影响,主要是体现在第二种攻击方式上,也就是攻击者会通过受影响的应用程序,利用漏洞对容器化的应用实施攻击。

一旦第一步漏洞利用成功,接下来就会按照通常的渗透攻击逻辑,一方面在主机执行恶意程序;另一方面通过横向移动,扩大攻击范围,这里的横向移动既会涉及主机层面的容器逃逸,也包括东西向网络层面的移动攻击。

1.2 如何快速响应处置

云原生架构下,在漏洞的应急响应上,总体思路和传统安全事件的应急是一致的。首先需要对漏洞的原理以及可能被利用的方式进行分析,确定修复和缓解方案,同时制定相关安全产品的防护规则,实现对漏洞利用的检测和拦截,最后就是有条不紊的进行漏洞的修复和处置。


在容器环境中,具体可以梳理出如下的一些关键操作步骤:

•  首先,需要确定现有业务的受影响范围。例如:确定仓库中所有受漏洞影响的镜像,确定受影响的线上业务;

•  其次,升级相关安全产品的防护策略。例如通过WAF规则以及防火墙规则等实现对漏洞利用的攻击进行一定程度的暂时性拦截;必要时升级运行时检测策略,一旦入侵成功,可以快速的发现并进行处置。

•  最后,就是修复漏洞,升级到官方发布的修复版本。

1.2.1 为什么不容易

安全应急或者安全运营的效率,很大程度上依赖安全能力的建设。上述处置步骤,相对来说是理想情况下的一种处置流程,或者是需要在一套完善的安全能力建设基础之上才可以轻松实施的处置流程。

根据腾讯云在2021年11月份发布的《腾讯云容器安全白皮书》显示,当前云原生用户在安全能力的建设上可谓是参差不齐,像镜像漏洞扫描、主机安全加固以及集群监控审计等基础安全能力,落地部署的比例也仅仅只有50%左右,甚至有7%的用户在云原生的使用时没有任何安全能力的部署。

从log4j2漏洞看云原生架构下的安全建设与安全运营

因此,在这样的现状下,面对log4j2这样的0day漏洞,在应急处置上,难免会出现各种捉襟见肘的问题。

1.2.2 控制影响范围

对于漏洞的处置,首先就是控制漏洞影响范围。因为漏洞的修复需要一定的时间周期,像log4j2这种使用范围如此之广的组件,甚至有预测,漏洞影响将会持续很长一段时间,因此控制新的影响资产增加也是十分重要的。


这里主要体现在两个方面:

(1)防止包含漏洞镜像的入库。CI集成以及镜像入库等阶段,需要严格进行安全检查,防止漏洞的引入。

(2)防止包含漏洞镜像的运行。在新的服务启动运行时,需要检测相关镜像是否包含漏洞,对于未通过安全检测的镜像,要严格阻止其启动运行。


1.2.3 怎么确定受影响范围

1)识别所有受到漏洞影响的镜像

在确定业务的受影响范围时,如果部署了容器镜像安全扫描的能力,安全厂商通常会在第一时间更新漏洞库或检测规则,用户可以直接通过对镜像仓库的所有镜像进行扫描发现受影响的镜像。

如果没有部署镜像安全扫描,腾讯云容器安全服务提供7天的免费试用,用户可以通过其中的镜像扫描功能,对镜像资产进行排查。最差情况下,用户可以使用开源的镜像扫描工具(例如Clair/Anchore/Trivy等)进行问题排查,但是有一点需要注意,使用开源工具前,要确保漏洞库或者检测规则已经包含了对目标漏洞的检测。

2)识别受影响的运行工作负载

当确定了受影响的镜像后,就需要根据这个列表确定受影响的线上业务。假如我们的日常安全运营做的足够完善,理论上这个列表跟受影响的业务列表应该是一致的。或者是我们需要部署相应的安全能力,实现镜像资产到线上业务资产的映射。

假如这些都没有的话,就需要逐个集群的检索当前使用的镜像,判断其是否受到影响,例如可以使用“kubectl describe pods --all-namespaces| grep image”这种最粗暴的指令获取集群运行业务所使用的所有镜像。到这里我们发现,如果仓库中镜像的数量太多,其实也可以采用另一种思路,先使用类似“kubectl describe pods --all-namespaces| grep image”这样的命令,逐个集群查询到所有线上业务使用的镜像,然后对于这些镜像定向的进行漏洞检测。


1.2.4 怎么修复

面对漏洞的爆发,所有人都希望能充分了解这个漏洞,并在第一时间使用对应的补丁解决问题。不幸的是:一方面,软件开发和测试需要时间周期,漏洞的修复不会那么快;另一方面,在微服务架构下,受影响的镜像可能会非常多,这同样给漏洞的修复带来很大的挑战。因此,在漏洞修复的同时,我们可以通过建议的缓解措施进行缓解,例如,对于log4j2漏洞,可以添加jvm启动参数:-Dlog4j2.formatMsgNoLookups=true进行暂时的缓解。

但是,在云原生架构下,应用程序的启动命令以及运行参数等信息,都是直接打包在镜像中,这样又回到前文提到的问题,如果受影响的镜像数量非常庞大的时候,这种临时的缓解措施在实施起来也将面临重大的挑战。


在云原生架构下,我们看到可以有几种针对漏洞的缓解性操作:

(1)修改线上运行环境

我们可以通过kubectl edit pod…命令,修改线上服务Pod的运行参数,实现漏洞的缓解。针对批量的运行参数修改,我们也推出了一个开源的工具 。值得注意的是,上述处置方式在修改完参数之后,会自动重启服务,用户在使用时,需评估相应的重启风险。


(2)利用漏洞特性缓解

以log4j2为例,这是个远程任意代码执行的漏洞,简单来说,就是在打印日志时,如果发现日志内容中包含关键词 ${,那么这个里面包含的内容会当做变量来进行替换,导致攻击者可以任意执行命令。

因此在进行漏洞缓解时,可以利用漏洞的这一特性,将缓解指令通过漏洞传进去,实现利用漏洞来缓解漏洞的效果。

这种方法针对不同的漏洞,不具有普适性。

(3)漏洞利用的阻止

前面两种操作,都是从漏洞本身出发,通过缓解方式,使得漏洞不能被利用。另外一种缓解措施就是一旦前述缓解措施失效或被绕过,可以在漏洞利用的关键路径上,进行操作的拦截,从而达到漏洞缓解的效果。

这种操作对安全能力有一定的依赖,一方面,安全能力需要能够检测出漏洞利用的行为,另一方面,需要能够精准的对进程行为进行阻断。尤其是对于log4j2这种任意代码执行的漏洞,漏洞利用的检测对安全能力有着较高的要求。


通过上述几种临时缓解措施后,接下来我们需要做的就是,结合线上环境使用的镜像以及业务重要性和优先级等因素,有条不紊的将受影响的组件升级至官方发布的稳定修复版本。

1.3 云原生安全运营的挑战和优势

从上述漏洞处置的过程我们可以发现,云原生架构下在漏洞的处置修复上,容器环境既面临一定的挑战,同时也有着一定的优势。

1.3.1 挑战

1)镜像数量大。

一方面,由于log4j2本身就是应用范围很广的组件,而且在微服务架构下,应用又会进行很多细粒度的微服务拆分,因此在仓库中会受影响的镜像会涉及到很多个Repositories;另一方面,由于DevOps等敏捷开发流程的使用,镜像仓库中的每一个镜像又会有很多个版本(每个Repository有很多个Tags)。因此,在漏洞处置的过程中会发现,扫描出来的受影响镜像数量巨大。

2)僵尸镜像。

所谓的僵尸镜像,其实可以理解为存储在仓库中的旧版本镜像,或者过期镜像,已经几乎不会再被运行使用。如果对仓库中的镜像没有很好的管理机制,这种僵尸镜像的数量也会非常大。这种现象其实也很好理解,DevOps带来业务快速的迭代,自然就会产生大量的过期镜像。在常规的安全运营中,这些僵尸镜像原则上是应该及时被清除的(不需要考虑备份回滚的问题,代码仓库会有),这种清除操作不仅仅是需要覆盖镜像仓库,同样适用于主机上的僵尸镜像。

3)不可变基础设施。

云原生架构的一个典型特征就是不可变的基础设施,所谓的不可变基础设施,是指一旦部署了服务之后决不允许被修改。如果需要以任何方式更新、修复或修改某些内容,则需要修改相对应的镜像,构建全新的服务镜像来替换旧的需要改变的服务镜像,经过验证后,使用新的镜像重新部署服务,而旧的则会被删除。

这种特性,给我们针对线上业务在进行漏洞缓解的时候带来了很大的不便。一方面体现在修改应用的运行参数和环境变量等信息上;另一方面体现在这种缓解措施的修改,会引发运行时安全的再次告警,因为这种操作违背了不可变基础设施的要求,不是正常的业务操作流程。

1.3.2 优势

1)资产可视化,快速定位。

资产问题一直是安全建设和安全运营中重要的问题,同时也是最让人头疼的问题。云原生架构很好的解决了资产的问题,通过Kubernetes等编排平台以及镜像仓库等组件,可以让我们快速的进行资产梳理、问题定位。

2)流程自动化,快速生效。

Kubernetes等编排平台提供了一整套的业务自动化管理方案,包括配置管理、服务编排、任务管理等。因此,对于漏洞的修复可以实现快速分发和对应的灰度升级等。

3)安全左移,快速控制。

能够在CI/CD等多个环节进行安全左移检测,镜像入库前的检测,阻止包含漏洞镜像推送到仓库,降低增量风险;在运行时进行准入检测,对于包含漏洞风险的镜像,阻止其启动运行,减小线上环境新增暴露面。

4)微服务架构。

在微服务架构下,应用间相对独立,这给漏洞修复带来的好处,一方面,针对某个镜像的漏洞修复,影响范围小,提高漏洞修复效率;另一方面,微服务架构下,服务功能单一,很多重复的功能会形成独立服务,这样减小了修复数量。



前文中,我们简要分析了对于log4j2这样的重大安全漏洞,在云原生架构下该如何快速进行应急和修复,以及云原生架构对于这种安全应急所带来的挑战和优势。事件过后我们需要痛定思痛,系统的来思考下,面对云原生架构如何进行有效的安全建设和安全运营,使得我们在安全事件的处置上可以做到游刃有余。

腾讯云容器服务TKE目前拥有国内最大规模的Kubernetes集群,运行了包括游戏、支付、直播、金融等多个应用场景。而集群的稳定运行离不开安全能力的保驾护航,腾讯云容器安全服务TCSS掌握了业内最前沿的云原生安全视角,为TKE的安全治理提供持续指导并沉淀了丰富的思考和最佳实践。

2 云原生架构下的安全建设与安全运营

安全运营是目标,安全能力是手段。

安全能力的建设与安全运营有着紧密的关系,安全能力建设是安全运营的基础,巧妇难为无米之炊,更好的安全能力建设可以使安全运营更加顺畅,同样安全运营也能给安全能力建设提供更好的输入和反馈,使安全检测和防护能力更加精准。

云原生架构下的安全能力建设和运营,其实是一个很大的命题,限于篇幅本文不会完全覆盖。本文主要围绕log4j2漏洞这个典型场景,从安全运营的视角,分析安全能力建设的必选项。

2.1 传统的安全能力建设必不可少

首先需要说明的是,不管是我们现在讲的容器安全,还是云原生安全,都是一个相对狭义的概念,通常只包含了云原生架构下特有安全风险的检测与防护。从安全风险角度来看,我们也一直强调,云原生架构下的安全风险是一个增量,因此在整体的安全建设上,一定是个纵深防御的体系,不是某个产品单打独斗所能完成的。

例如南北向流量出入口的WAF、防火墙、抗D等,假如我们的云原生是建立在IaaS基础之上的,那么VPC、甚至是underlay层面的网络分级分域的隔离和入侵检测,这些都是云原生安全建设的基础。在这次log4j2漏洞的应急处置中,我们也发现,即使是容器环境,通过升级WAF规则、更新防火墙出站策略等方式,也能在第一时间实现一定程度的漏洞缓解和阻断。

腾讯云在2021年11月发布的《腾讯云容器安全白皮书》中,也提出了层次化的容器安全体系框架,其中很重要的一部分就是基础安全,这里的基础安全就是包括了原有的数据中心安全以及云安全建设所覆盖的内容。

2.2 安全运营驱动安全能力建设

对于体系化的安全建设和安全运营,一些技术组织以及标准化组织,也提出过相关的标准框架,这些框架对于我们在安全建设上,都有着重要的指导和参考意义,这里我们以NIST提出的网络安全框架 为例来作为我们云原生安全建设的参考。

参考NIST网络安全框架,我们同样将云原生安全建设划分为五个并行并且连续的步骤,分别是识别、防护、检测、响应和恢复。

2.2.1 安全识别

1)集群资产识别

安全识别最主要是体现在资产识别上。这里的资产既包括cluster、node、namespace、pod、service、container等Kubernetes资源层面的资产,同样还包括镜像仓库、容器镜像等维度的应用资产信息。

云原生架构下,除了基本的资产识别盘点之外,还需要能够发现这些资产之间潜在的资源和业务之间的逻辑关系。这样一旦检测到某个镜像包含新的漏洞,或者检测到相应的入侵行为,需要能够快速进行所有资产和人员的自动化关联定位,发现影响范围,以及定位安全责任人,进而快速进行处置。

2)自建容器识别

除了对于标准集群层面的资产具备上述识别能力外,对于研发系统等相对复杂的环境同样需要有一定的适配能力。例如,在研发环境中,除了标准集群层面的资产外,还会出现自建的资产,例如用户用Docker run等命令直接拉起运行的容器。

3)业务风险识别

从安全运营角度看,安全识别还体现在业务风险识别上。我们需要对集群、应用进行清晰的安全风险级别划分,对于高风险应用,需要采用更高级别的安全策略。例如,对于核心业务系统,要有严格的网络隔离以及访问控制机制,对于直接暴露出去的服务,在容器维度要有更加严格的权限控制等。

2.2.2 安全防护

具备资产以及业务风险信息后,接下来就需要依赖基本的安全防护能力,实现对已知威胁的安全防护。这里的安全防护主要包括两个方面:

(1)系统加固

• 配置检测与修复

系统加固可谓是个老生常谈的话题了,尤其是配置检查与安全配置加固,但是在云原生架构下,这一点是尤为重要的。因为从容器的设计理念来看,其与操作系统共享内核,给了容器用户更大的可操作空间,因此,配置的安全与否将在很大程度上影响着整个系统的安全性。

从前文的容器环境主要入侵路径可以看出,通过主机攻击容器是其中重要的一种路径,例如通过Docker Remote API。因此安全能力需要包括全面的配置检查。

配置加固虽然说起来是个老问题,但是在云原生环境中,真正实现完整的安全能力还是比较复杂,这既包括Kubernetes、Docker、Istio等基础平台与组件的加固,还包括镜像内应用软件的配置加固,这个做起来就更复杂一些。我们在这里就不再展开。

从安全运营角度看,我们需要能够根据配置检查得到的信息,将基本的配置进行安全性加固。同时一个重要的点就是,安全配置与业务稳定运行之间的平衡,一方面需要保证充分实现了安全性,另一方面就是不会对业务的可用性和稳定性造成影响。这就需要在配置加固的同时,结合业务特性与安全配置要求,灵活对配置策略进行调整,这将会是一个持续的修正和完善的过程。

•  漏洞检测与修复

已知漏洞修复同样是个古老的话题,包括主机层面的漏洞和镜像的漏洞,对于检测出来的漏洞,需要根据漏洞的威胁等级以及利用难易程度等信息,确定是否需要修复以及修复的优先级。

•  镜像安全评估与修复

容器镜像作为云原生应用的源头,除了漏洞之外,还需要进行更多维度的安全性评估。例如至少需要包含以下几个方面:镜像内敏感信息的检测,确保不会发生敏感信息泄露;镜像中病毒木马等恶意文件检测,这主要针对不确定来源的公开镜像;镜像构建的合规性检测,比如COPY和ADD的使用区别等。

除了针对上述镜像风险的检测和修复之外,在安全运营上还需要考虑对僵尸镜像清理,这既包括对镜像仓库的清理,也包括对集群node节点的清理,这对于减小攻击面有着重要的作用。

同时,针对不同镜像需要支持自定义的检测规则,不同的组织用户或者不同类型业务的镜像,对安全的要求是不一样的,因此在镜像的安全评估上,除了基于一套通用的检测评价规则之外,还需要支持用户的自定义规则,这样可以结合前文的业务风险识别,针对不同的镜像,灵活采用不同的安全规则。

•  风险管理

在运营管理上,针对上述提及的配置、漏洞等风险信息,需要有一套完善的闭环风险管理流程,确保完全实现了风险的识别、修复以及确认。


(2)安全防护

除了系统加固外,在安全防护阶段,还应该在不同层面,针对已知可能发生的入侵风险,通过相关的防护能力和防护策略进行攻击的预防。

•  准入控制

准入控制顾名思义就是在云原生应用的全生命周期流程中,根据安全的要求,在不同的阶段进行控制和阻断,进而实现安全性的目标,这也是DevSecOps的一项基本要求。云原生架构凭借其灵活的资源管理与自动化的应用编排,给安全性的控制提供了充分的便利。准入控制的价值,一方面体现在安全风险的预防上,另一方面,一旦log4j等重大0day爆发后,可以通过准入控制,快速控制影响面,防止风险新增。

从生命周期流程看,准入控制需要分别从研发(dev)和运行时(ops)两个阶段来实施。研发阶段的准入主要指在CI、入库等阶段,进行漏洞、敏感信息之类的安全风险的检测,只有符合安全要求后,才允许进入流水线的下一个阶段。这里的准入条件通常需要涵盖前文讲的各种加固内容。

运行时的准入控制,则主要体现在应用被部署运行的阶段,只有符合安全要求的容器/pod,才允许被拉起运行,这里的准入条件通常包括对资源限制的检测、对syscall/capability等权限限制的检测等。

同样,从运营的角度看,准入控制规则除了标准默认的之外,还需要能够根据应用进行灵活则调整和完善。

•  运行时拦截

云原生架构下的容器内,承载的是微服务应用,因此理论上是不应该具备高权限指令的执行,这一点我们在准入控制虽然做了一定程度的预防。这里我们基于运行时安全能力,还需要实现对容器内高危操作的拦截,例如高危命令、高危系统调用等,在不同维度实现安全的纵深防御。

•  网络隔离

横向扩展是攻击者在实现第一步攻击之后的操作,也可以称为后渗透阶段。在云原生网络的设计中,通常默认是不具备任何网络隔离能力的,因此,需要设置并实现一套完善的网络隔离机制,实现不同业务之间的网络隔离。

云原生架构下的网络组织形态,区别于传统的基于主机或者虚拟机的网络,在Kubernetes中,网络的最小单位是Pod,而Pod中承载的是业务容器。因此,在实现网络隔离的时候,传统的基于IP、端口的网络策略将不再适用,我们需要基于label、service等资源,实现不同粒度的网络隔离。

•  防护策略管理

在运营过程中,如何设置准入控制、操作拦截、网络隔离等策略,这是一个令人头疼的问题,因为无论是安全管理员、运维管理员,甚至是开发人员,都很难完全讲得清楚这些规则该如何配置,才能实现相对最安全的状态。

这是云原生架构下安全运营的一个挑战,同时云原生架构本身也提供应对这种挑战的优势。前文提到云原生架构的一个重要特性就是不可变的基础设施,这就意味着,我们可以通过白名单、行为模型等方式,基于业务特性以及历史运行数据,自动化的学习生成一套安全基线,这个安全基线将成为各种防护策略配置的重要参考。

2.2.3 安全检测

安全永远是一个攻防博弈的过程,而防守方往往处于相对劣势的地位,甚至可以说没有攻不破的系统。

在云原生架构下,业务变得越来越开放和复杂,攻击者的手段越来越多样化,前文所述的防御拦截措施,总是难以应对所有的威胁,有些高级定向攻击或者是像针对log4j2这种0day漏洞的攻击,总是可以轻易的绕过各种防御手段,让安全威胁防不胜防。

因此,在完成了上述所有的防御拦截措施之后,还需要持续的对云原生系统进行运行时监测以及安全检测。基于云原生架构的特性,这里将安全检测分为两个维度来进行。

1)系统维度的威胁检测

主要针对容器内的行为来进行,比如容器内进程异常的检测、文件异常的检测、用户异常的检测等,通过这些细粒度的异常检测,发现诸如提权、挖矿等攻击行为。

2)网络维度的威胁检测。主要面向的是后渗透阶段的横向移动,虽然我们在防护阶段已经设置了严格的访问控制策略,但是在网络可达范围内的横向移动攻击,仍然会带来重要的安全威胁。网络威胁检测主要分为两个方面:一方面是从网络行为的角度,基于Flow实现网络流量尤其是东西向流量的异常检测,这对于端口探测、APT攻击,甚至是新型的网络威胁或者高级的网络威胁等检测将会起到重要的帮助(NDR);另一方面就是从数据包的角度,分析容器之间网络的数据包异常,实现容器网络的入侵检测(NIDS)。

3)应用维度的威胁检测

同样面向是后渗透阶段的横向移动,云原生时代应用的微服务架构使得容器间的网络通信会存在大量的API调用,确保所有这些API之间调用都是安全的,对于云原生应用的安全有着重要的意义。例如,在已攻陷的容器中,通过API的方式获取其他服务的数据、或者是通过构造恶意的参数实现对关联服务的攻击。因此,需要在应用的维度实现对API调用异常的检测,比如调用行为、调用路径、调用参数等。

2.2.4 安全响应

安全响应主要是针对前一个步骤的安全检测告警所做出的处置措施。在云原生架构下的安全响应,尤其是网络安全层面的安全响应,我们更倾向于使用旁路检测响应处置这样的操作步骤,而不是像传统网络安全中串联接入IPS、WAF这种直接阻断式的检测响应,这样的设计主要是从业务性能的角度出发。

威胁的响应主要也是包括两个方面:

(1)处置

通过网络隔离、暂停容器、停止异常进程、销毁容器等方式,实现对告警的响应处置。这里有一个前提,就是在安全能力的建设过程中,鉴于容器的短生命周期特性,需要实现完善的日志和追踪记录,以便实现处置后的溯源取证。处置的过程中,对于某些确定性异常,可以通过一键阻断、一键隔离等方式,实现处置操作的自动化,以降低运营成本。

(2)溯源

根据容器的告警、日志、追踪等数据以及数据间的关联分析,实现对告警的溯源分析,明确攻击链路,确定入侵原因。

2.2.5 安全修复

在安全修复阶段主要包括两个方面的内容:一方面就是针对入侵原因,对相关风险进行加固性修复;另一方面,就是从加固、防护、检测等步骤,分别更新相关的安全策略,实现运营反馈。

3 总结

Log4j2漏洞已经过去了一个多月,相信很多该打的补丁都已经修复完毕,这次突发的应急事件,是否让我们需要重新思考云原生架构下的安全建设和安全运营。漏洞或者入侵很难预测,不知道下一次什么时候还会发生,痛定思痛,到那时我们能否可以从容应对。

希望本文的思考能给云原生安全建设带来一些思路和帮助,如有任何建议或疑问,欢迎文末留言。



文章转载自“云鼎实验室”。点击阅读原文了解更多。