type
status
date
slug
summary
tags
category
icon
password

利用Kubernetes探针进行持久化的攻防观察与防护
一、引言
Kubernetes作为现代容器编排平台的事实标准,提供了强大的探针机制来确保容器化应用的可靠性和可用性。这些探针(Probes)本意是用于健康检查,帮助Kubernetes自动重启失败的容器、不将流量发送到未准备好接收流量的容器,从而大大提高应用的稳定性和自愈能力。然而,正如许多安全机制一样,探针的设计特性也可能被攻击者滥用,成为实现持久化(Persistence)的工具。本文将深入探讨Kubernetes探针的工作原理,分析它们如何被攻击者利用来实现持久化,并提供相应的防御策略和最佳实践。
二、Kubernetes探针概述
1. 探针类型
Kubernetes定义了三种主要类型的探针,每种探针都有其特定的用途和触发条件:
(1) 存活探针(Liveness Probe)
存活探针用于确定容器是否正在运行。如果存活探针失败,Kubernetes将视为容器不健康,并尝试重新启动容器。这对于检测应用程序内部的假死情况非常有用,例如,如果Web服务器停止响应请求。存活探针的主要目的是确保应用程序正在运行,如果应用因死锁或其他原因卡住,自动重启可能恢复应用。
(2) 就绪探针(Readiness Probe)
就绪探针用于确定容器是否已准备好接收网络流量。如果就绪探针失败,Kubernetes将停止将流量发送到容器,以确保不会将流量发送到尚未准备好的容器。这有助于避免将流量发送到正在启动或尚未加载数据的应用程序。就绪探针的主要应用场景是控制那些需要加载大量数据或配置文件的应用,直到应用准备好接受流量前,不将请求路由到该容器。
(3) 启动探针(Startup Probe)
启动探针是Kubernetes 1.16版本引入的新功能,用于确定容器是否已成功启动。与存活探针不同,启动探针仅在容器启动时执行,一旦启动探针成功,就绪和存活探针将接管后续的检查。启动探针的主要应用场景是对于启动时间较长的应用,确保不会因为启动慢而被误判为失败状态。当配置了启动探针后,会先禁用其他探针,直到启动探针成功后,其他探针才会继续,防止存活探针无限重启应用。
2. 探针检查类型
每种探针都可以配置为执行以下类型的检查之一:
(1) HTTP GET请求
对指定的端口和路径执行HTTP GET请求。如果返回的状态码在成功的范围内(默认为200-399),则认为检查成功。这种方式适用于提供HTTP接口的应用程序。
(2) TCP Socket检查
尝试与容器的指定端口建立TCP连接。如果连接成功建立,则认为检查成功。这种方式适用于基于TCP的服务,但不一定提供HTTP接口。
(3) 执行容器内的命令
在容器内执行指定的命令。如果命令执行后退出状态码为0,则认为检查成功。这种方式提供了最大的灵活性,可以执行自定义的健康检查逻辑。
3. 探针配置参数
探针的配置包括多个参数,这些参数决定了探针的行为和触发条件:
initialDelaySeconds
:容器启动后等待多长时间才开始执行探针检查,单位为秒。
periodSeconds
:执行探针检查的时间间隔,单位为秒,默认为10秒。
timeoutSeconds
:探针检查的超时时间,单位为秒,默认为1秒。
successThreshold
:探针检查成功后,最少需要连续成功多少次才被认为是成功,默认为1次。
failureThreshold
:探针检查失败后,最多允许连续失败多少次才被认为是失败,默认为3次。对于存活探针,达到失败阈值后会重启容器;对于就绪探针,达到失败阈值后会认为容器未就绪。
三、探针被滥用的方式
虽然探针的设计初衷是为了提高应用的可靠性和可用性,但攻击者可以利用探针的特性和配置参数来实现持久化。以下是探针被滥用的主要方式:
1. 调度节奏作为定时器
探针的
periodSeconds
参数决定了探针的执行周期,攻击者可以利用这一特性将探针变成定时器,实现定期执行恶意操作:- 通过设置较短的
periodSeconds
,攻击者可以实现频繁的定时执行,例如每60秒执行一次恶意操作。
- 通过设置较长的
initialDelaySeconds
,攻击者可以延迟探针的首次执行,避开上线初期的检测和监控。
2. 失败策略作为自复活或隐身机制
探针的失败处置机制为攻击者提供了实现自复活或隐身的能力:
- 存活探针的失败策略:存活探针失败会重启容器,攻击者可以通过构造特定条件下的存活探针失败,实现容器的周期性重启。这种机制可以被用来"洗掉"容器内的短驻痕迹(如内存中的恶意进程或临时文件),同时通过持久卷或外部存储维持恶意状态,达到"杀不死/删痕迹"的效果。
- 就绪探针的失败策略:就绪探针失败不会重启容器,只会停止向该容器发送流量。攻击者可以利用这一特性,使容器在后台持续运行但不接收正常流量,从而实现隐蔽的恶意活动。
- 启动探针的失败策略:启动探针在完成前会屏蔽其他两类探针,攻击者可以利用超长的启动探针延迟,使可疑行为在"稳定运行一段时间后"才出现,错开变更窗口和监控重点时段。
3. 执行介质作为触点
探针的三种检查方式为攻击者提供了不同的执行介质,每种方式都有其特定的滥用场景:
- HTTP GET:攻击者可以将
httpGet.host
指向外部域名或IP地址,形成稳定的"命令与控制(C2)"通道或心跳机制。通过控制回包的状态码,攻击者可以远程控制探针的成功或失败,从而驱动容器重启或流量切换。
- TCP Socket:攻击者可以利用TCP探针对单一外部主机或端口进行周期性连接尝试,这可以被用作端口探测或"存活信标",表明恶意代码仍在运行并可以接收指令。
- Exec:这是风险最高的形式,攻击者可以将健康检查变成"周期任务执行器"。如果容器还具备高权限或敏感挂载,则具备强大的干扰能力。例如,攻击者可以配置Exec探针定期执行下载恶意代码、窃取数据或建立反向连接等操作。
四、持久化场景分析
基于上述滥用方式,攻击者可以构建多种持久化场景,以下是几种典型的场景分析:
1. 伪Cron任务
攻击者可以通过配置存活探针或就绪探针,结合较短的
periodSeconds
和Exec或外部HTTP目标,实现准时的后台行为,类似于Linux系统中的Cron任务:这种配置会使容器每60秒执行一次从恶意服务器下载并执行脚本的操作,实现持久化的恶意行为。
2. 自复活与洗痕
攻击者可以构造必定失败的存活探针,强制容器周期性重启,同时将恶意状态保存到持久卷或外部存储中:
这种配置会使容器在检测到
/tmp/malicious-flag
文件不存在时失败,从而触发重启。攻击者可以在容器启动时创建该文件,并在特定条件下删除它,触发重启。通过这种方式,攻击者可以实现"杀不死"的效果,同时通过频繁重启"洗掉"容器内的短驻痕迹。3. 隐蔽心跳通联
攻击者可以将HTTP或TCP探针指向外网,利用"健康检查"的合理性降低流量审计敏感度:
这种配置会使容器每60秒向恶意服务器发送一次HTTP请求,作为心跳信号。由于这是Kubernetes的正常健康检查行为,可能会被安全监控忽略。
4. 延迟潜伏
攻击者可以配置超长的启动探针延迟,使可疑行为在"稳定运行一段时间后"才出现:
这种配置会使启动探针在容器启动后的300秒(30次失败 × 10秒间隔)内持续检查,直到成功为止。在这段时间内,其他探针被禁用,攻击者可以利用这一窗口期执行恶意操作,而不会触发存活或就绪探针的检查。
5. 模板化扩散
攻击者可以通过Admission Webhook或Operator注入探针模板,将恶意探针配置自动注入到新创建的Pod中,实现横向扩散:
这种配置会在新Pod创建时自动注入恶意探针,使恶意行为能够跨命名空间持续存在。
五、蓝队能抓到的信号
防御方可以通过多种渠道检测到探针被滥用的迹象,以下是关键的检测信号:
1. 配置面信号(API审计/清单比对)
- 任意包含
.probe.exec
的Pod配置,特别是执行可疑命令的Exec探针。
httpGet.host
指向非空且非内网/非集群域名的HTTP探针。
- 极端参数配置:
periodSeconds
小于10或大于300;timeoutSeconds
大于30;failureThreshold
大于10或接近最大值2147483647。
- 同一命名空间里出现"模板化相同"的探针配置,疑似被自动注入。
2. 运行面信号(节点/网络/日志)
- 出口侧稳定出现User-Agent为
kube-probe/*
的外联请求,目标为非常见域名/IP。
- Pod重启计数异常上升,但readiness长期不就绪或频繁抖动。
- kubelet事件中"Liveness/Readiness probe failed"比率异常。
- 容器内出现严格的等间隔事件节拍,表明可能被用作定时器。
3. 资产面信号
- DaemonSet/Operator/Webhook的突然出现或修改,与探针行为同时段相关。
- 新增的持久卷声明或配置映射,可能与探针配合使用以保存状态。
- 异常的服务账户或角色绑定,可能用于扩大探针的权限范围。
六、可立即落地的拦截与基线
针对探针滥用的防御,组织可以采取以下具体措施:
1. 准入策略(Kyverno示例)
(1) 禁止在探针中使用exec
(2) 限制HTTP探针的主机
(3) 限制探针参数边界
2. 准入策略(Gatekeeper/OPA方向)
同样的思想可用Rego编写ConstraintTemplate:拒绝probe.exec,限制httpGet.host与参数区间。建议把"白名单域/网段"抽成Constraint参数,便于各环境复用。
3. 网络与边界控制
- 在出口代理/网关对User-Agent为
kube-probe/*
的请求建立白名单域,非白名单一律阻断或告警。
- 缺省NetworkPolicy设为"拒绝出站",按需放行到服务依赖域名/IP;健康检查走服务网格/本地探针尽量不经外网。
- 使用CNI网络插件的网络策略功能,限制Pod之间的通信,特别是对外的通信。
4. 运行与监控
- 将kubelet事件与容器重启计数接入告警:针对"短时间内重启次数激增""Probe Failed比率飙升"的规则化阈值。
- 维护"平台模板"的探针写法基线,新建工作负载偏离模板立即进入变更复核。
- 使用Prometheus等监控工具收集探针相关的指标,设置合理的告警规则。
5. 平台约束与教育
- 平台默认关闭exec探针;由平台团队提供"只读二进制"的健康检查程序供调用。
- 代码评审/CI阶段扫描*.yaml是否存在异常探针配置,左移发现。
- 对开发人员进行安全培训,提高他们对探针安全风险的认识。
七、与探针串联的持久化"组合拳"
探针滥用通常不是孤立存在的,攻击者会将其与其他技术结合,形成更复杂的持久化策略:
1. Admission Webhook/Operator注入
将上述探针模式自动注入新Pod,形成横向扩散。这种技术可以使恶意行为在集群内广泛传播,即使某些Pod被发现并清除,新的Pod仍会被注入恶意探针。
2. DaemonSet全节点铺开
把"周期心跳/自复活"推至每个节点,增强生存性。通过DaemonSet,攻击者可以确保每个节点上都有一个运行恶意探针的Pod,即使某些节点被隔离或重启,恶意行为仍能持续存在。
3. 与持久卷/外部存储配合
即使容器频繁重启,状态仍跨重启存在,构成真正的"持久化"。攻击者可以将恶意代码、配置或数据存储在持久卷或外部存储中,通过探针定期访问或更新,实现持久化的恶意行为。
4. 与RBAC后门结合
通过创建高权限的服务账户和角色绑定,扩大探针的权限范围,使其能够访问更多的集群资源或执行更危险的操作。例如,探针可能被配置为定期创建新的Pod或修改现有的资源,实现更复杂的攻击链。
八、防御手段
Kubernetes探针本质上提供了"节拍器 + 失败处置 + 执行介质"三件套。只要被滥用,就能实现相当隐蔽且韧性强的"持久化"。从防御角度,关键在于:
- 禁用或最小化exec探针;
- 给参数设边界、设模板化基线;
- 严控出网去向并对kube-probe流量建白名单/告警;
- 把"探针异常"纳入日常可观测性与审计。
防御探针滥用的关键在于深度防御:从准入控制到网络隔离,从监控告警到审计日志,多层次的安全措施可以大大降低探针被滥用的风险。同时,安全意识和最佳实践的普及也是防御的重要组成部分,只有整个组织都认识到探针安全风险并采取相应的措施,才能真正有效地防止探针被滥用。
在未来的云原生环境中,随着Kubernetes的普及和复杂性的增加,探针等机制的安全问题将变得更加重要。组织需要持续关注最新的安全威胁和防御技术,不断更新和完善自己的安全策略和措施,以应对不断变化的安全挑战。

